2011-02-28 92 views
1

我在我的代碼中調用了一個批處理文件並給出了某些參數。這個批處理文件調用另一個批處理文件等。整個過程大約需要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

回答

1

最可能的原因是批處理文件正在寫入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(); 
1

如果你感到快樂拿起在最後的輸出(即你不需要作爲進程運行,以顯示它),只需使用CMD.EXE重定向它:

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