需要很长时间的运行过程

问题描述:

我在我的代码中调用了一个批处理文件并给出了某些参数。这个批处理文件调用另一个批处理文件等。整个过程大约需要45分钟才能完成。我还需要等待批处理文件完成,然后再继续执行其余的代码(清理批处理文件等)。需要很长时间的运行过程

我的问题是,虽然我已经尝试了几个不同的东西,但我无法获得批处理文件,既要完成其运行,也要将其输出写入日志文件。

这里是我做了什么让批处理文件来完成其运行:

Process process = new Process(); 
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(filename); 
process.StartInfo.UseShellExecute = false; 
process.StartInfo.CreateNoWindow = false; 
process.StartInfo.FileName = filename; 
process.Start(); 

process.WaitForExit(); 

在尝试启用日志记录我已经尝试了不少的东西。这只是最新的尝试。

Process process = new Process(); 
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(filename); 
process.StartInfo.UseShellExecute = false; 
process.StartInfo.CreateNoWindow = true; 
process.StartInfo.RedirectStandardOutput = true; 
process.StartInfo.FileName = filename; 
process.Start(); 

StreamReader sr = process.StandardOutput; 
StreamWriter sw = new StreamWriter(exelocation + @"Logs\" + version + "\\" + outputname + ".txt"); 

while (!process.HasExited) 
{ 
     sw.Write(sr.ReadToEnd()); 
} 

此代码基本上它使一个微不足道的部分首批文件中的一个,并停在那里。批处理文件在一分钟之内运行。我不明白为什么会发生这种情况。如果标准输出没有被重定向并且窗口被创建,它会完美运行,但如果窗口被隐藏并且标准输出被重定向,它什么也不做?

+0

把一个破发点线'sw.Write(sr.ReadToEnd());',看看是否过线完成执行并进入下一个循环 – 2011-02-28 16:38:11

最可能的原因是批处理文件正在写入StandardError流,并且缓冲区已满。

管理标准流的重定向非常棘手。您需要异步读取两个流,如果要捕获所有输出,可能需要合并它们。我有一个类,这是否:

/// <summary> 
/// Reads streams from a process's <see cref="Process.StandardOutput"/> and <see cref="Process.StandardError"/> 
/// streams. 
/// </summary> 
public class ProcessOutputReader 
{ 
    /// <summary> 
    /// Builds the combined output of StandardError and StandardOutput. 
    /// </summary> 
    private readonly StringBuilder combinedOutputBuilder = new StringBuilder(); 

    /// <summary> 
    /// Object that is locked to control access to <see cref="combinedOutputBuilder"/>. 
    /// </summary> 
    private readonly object combinedOutputLock = new object(); 

    /// <summary> 
    /// Builds the error output string. 
    /// </summary> 
    private readonly StringBuilder errorOutputBuilder = new StringBuilder(); 

    /// <summary> 
    /// The <see cref="Process"/> that this instance is reading. 
    /// </summary> 
    private readonly Process process; 

    /// <summary> 
    /// Builds the standard output string. 
    /// </summary> 
    private readonly StringBuilder standardOutputBuilder = new StringBuilder(); 

    /// <summary> 
    /// Flag to record that we are already reading asynchronously (only one form is allowed). 
    /// </summary> 
    private bool readingAsync; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="ProcessOutputReader"/> class. 
    /// </summary> 
    /// <param name="process"> 
    /// The process. 
    /// </param> 
    public ProcessOutputReader(Process process) 
    { 
     if (process == null) 
     { 
      throw new ArgumentNullException("process"); 
     } 

     this.process = process; 
    } 

    /// <summary> 
    /// Gets the combined output of StandardOutput and StandardError, interleaved in the correct order. 
    /// </summary> 
    /// <value>The combined output of StandardOutput and StandardError.</value> 
    public string CombinedOutput { get; private set; } 

    /// <summary> 
    /// Gets the error output. 
    /// </summary> 
    /// <value> 
    /// The error output. 
    /// </value> 
    public string StandardError { get; private set; } 

    /// <summary> 
    /// Gets the standard output. 
    /// </summary> 
    /// <value> 
    /// The standard output. 
    /// </value> 
    public string StandardOutput { get; private set; } 

    /// <summary> 
    /// Begins the read process output. 
    /// </summary> 
    public void BeginReadProcessOutput() 
    { 
     if (this.readingAsync) 
     { 
      throw new InvalidOperationException("The process output is already being read asynchronously"); 
     } 

     this.readingAsync = true; 

     this.CheckProcessRunning(); 

     this.process.OutputDataReceived += this.OutputDataReceived; 
     this.process.ErrorDataReceived += this.ErrorDataReceived; 

     this.process.BeginOutputReadLine(); 
     this.process.BeginErrorReadLine(); 
    } 

    /// <summary> 
    /// Ends asynchronous reading of process output. 
    /// </summary> 
    public void EndReadProcessOutput() 
    { 
     if (!this.process.HasExited) 
     { 
      this.process.CancelOutputRead(); 
      this.process.CancelErrorRead(); 
     } 

     this.process.OutputDataReceived -= this.OutputDataReceived; 
     this.process.ErrorDataReceived -= this.ErrorDataReceived; 

     this.StandardOutput = this.standardOutputBuilder.ToString(); 
     this.StandardError = this.errorOutputBuilder.ToString(); 
     this.CombinedOutput = this.combinedOutputBuilder.ToString(); 
    } 

    /// <summary> 
    /// Reads the process output. 
    /// </summary> 
    public void ReadProcessOutput() 
    { 
     if (this.readingAsync) 
     { 
      throw new InvalidOperationException("The process output is already being read asynchronously"); 
     } 

     this.BeginReadProcessOutput(); 
     this.process.WaitForExit(); 
     this.EndReadProcessOutput(); 
    } 

    /// <summary> 
    /// Appends a line of output to the specified builder and to the combined output. 
    /// </summary> 
    /// <param name="builder">The target builder.</param> 
    /// <param name="line">The line of output.</param> 
    private void AppendLine(StringBuilder builder, string line) 
    { 
     builder.AppendLine(line); 
     lock (this.combinedOutputLock) 
     { 
      this.combinedOutputBuilder.AppendLine(line); 
     } 
    } 

    /// <summary> 
    /// Checks that the process is running. 
    /// </summary> 
    private void CheckProcessRunning() 
    { 
     // process.Handle will itself throw an InvalidOperationException if the process hasn't been started. 
     if (this.process.HasExited) 
     { 
      throw new InvalidOperationException("Process has exited"); 
     } 
    } 

    /// <summary> 
    /// Handles the ErrorDataReceived event on the monitored process. 
    /// </summary> 
    /// <param name="sender">The sender.</param> 
    /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param> 
    private void ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     if (e.Data != null) 
     { 
      this.AppendLine(this.errorOutputBuilder, e.Data); 
     } 
    } 

    /// <summary> 
    /// Handles the OutputDataReceived event on the monitored process. 
    /// </summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param> 
    private void OutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     if (e.Data != null) 
     { 
      this.AppendLine(this.standardOutputBuilder, e.Data); 
     } 
    } 
} 

下面是它的用法的例子:

var batchFile = Path.Combine(this.TestContext.TestSupportFileDir, "WriteToStandardError.bat"); 
var process = StartProcess(batchFile); 
var reader = new ProcessOutputReader(process); 
reader.ReadProcessOutput(); 
process.WaitForExit(); 

如果你感到快乐拿起在最后的输出(即你不需要作为进程运行,以显示它),只需使用CMD.EXE重定向它:

Process.Start("cmd.exe /c my.bat > my.log").WaitForExit();