在我的主要WPF应用程序代码中,我需要使用命令提示符运行.exe app。这个动作在backgroundworker中执行我有以下代码。代码正在运行带有命令提示符的readlines.exe应用程序,并将输出行读取为字符串(str)。
string str;
ProcessStartInfo proc = new ProcessStartInfo();
proc.WindowStyle = ProcessWindowStyle.Hidden;
proc.UseShellExecute = true;
proc.FileName = @"readlines.exe";
proc.Arguments = @"";
proc.UseShellExecute = false;
proc.RedirectStandardOutput = true;
proc.CreateNoWindow = true;
proc.RedirectStandardInput = true;
Process proc1 = Process.Start(proc);
proc1.StandardInput.WriteLine("");
str = proc1.StandardOutput.ReadToEnd();
我希望广告超时到以下行,所以当超时结束时,procces将被取消(如CTR + C)和" str"将得到输出文本,直到这一点。
str = proc1.StandardOutput.ReadToEnd();
有可能吗?
答案 0 :(得分:1)
虽然之前的答案已被接受,但这可能是一个更有用,更安全,更高效的解决方案。此外,它没有使用ReadLine()
方法,它会阻塞直到写入一行(可能永远不会发生)。它使用StringBuilder
的实例,并从流中读取可指定的数据块(默认大小为128个字符)。此外,它支持基于事件的读取数据通知。
班级的用法保持不变。
ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();
// Do whatever you want here
// (e.g. sleep or whatever)
por.StopReading();
// Now you have everything that has been read in por.Data
但是,我已添加OnDataRead
事件,每次读取新数据时都会触发该事件。您可以使用以下方式访问数据:以下代码:
...
// Subscribe to the event
por.OnDataRead += OnDataReadEventHandler;
...
回调方法/事件处理程序看起来像这样:
private void OnDataReadEventHandler(object sender, ProcessOutputReaderEventArgs e)
{
// e.IntermediateDataStore points to the StringBuilder instance which holds
// all the data that has been received until now.
string completeData = e.IntermediateDataStore.ToString();
// e.NewData points to a string which contains the data that has been received
// since the last triggered event (because the event is triggered on each read).
string newData = e.NewData;
}
修改后的ProcessOutputReader
类如下所示:
/// <summary>
/// Represents the ProcessOutputReader class.
/// </summary>
public class ProcessOutputReader
{
/// <summary>
/// Represents the instance of the thread arguments class.
/// </summary>
private ProcessOutputReaderWorkerThreadArguments threadArguments;
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReader"/> class.
/// </summary>
/// <param name="process">The process which's output shall be read.</param>
/// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified process reference is null.</exception>
public ProcessOutputReader(Process process)
{
if (process == null)
{
throw new ArgumentOutOfRangeException("process", "The parameter \"process\" must not be null");
}
this.Process = process;
this.IntermediateDataStore = new StringBuilder();
this.threadArguments = new ProcessOutputReaderWorkerThreadArguments(this.Process, this.IntermediateDataStore);
}
/// <summary>
/// Is fired whenever data has been read from the process output.
/// </summary>
public event EventHandler<ProcessOutputReaderEventArgs> OnDataRead;
/// <summary>
/// Gets or sets the worker thread.
/// </summary>
private Thread ReaderThread
{
get;
set;
}
/// <summary>
/// Gets or sets the intermediate data store.
/// </summary>
private StringBuilder IntermediateDataStore
{
get;
set;
}
/// <summary>
/// Gets the data collected from the process output.
/// </summary>
public string Data
{
get
{
return this.IntermediateDataStore.ToString();
}
}
/// <summary>
/// Gets the process.
/// </summary>
public Process Process
{
get;
private set;
}
/// <summary>
/// Stars reading from the process output.
/// </summary>
public void StartReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
return;
}
}
this.ReaderThread = new Thread(new ParameterizedThreadStart(ReaderWorker));
this.threadArguments.Exit = false;
this.ReaderThread.Start(this.threadArguments);
}
/// <summary>
/// Stops reading from the process output.
/// </summary>
public void StopReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
this.threadArguments.Exit = true;
this.ReaderThread.Join();
}
}
}
/// <summary>
/// Fires the OnDataRead event.
/// </summary>
/// <param name="newData">The new data that has been read.</param>
protected void FireOnDataRead(string newData)
{
if (this.OnDataRead != null)
{
this.OnDataRead(this, new ProcessOutputReaderEventArgs(this.IntermediateDataStore, newData));
}
}
/// <summary>
/// Represents the worker method.
/// </summary>
/// <param name="data">The thread arguments, must be an instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.</param>
private void ReaderWorker(object data)
{
ProcessOutputReaderWorkerThreadArguments args;
try
{
args = (ProcessOutputReaderWorkerThreadArguments)data;
}
catch
{
return;
}
try
{
char[] readBuffer = new char[args.ReadBufferSize];
while (!args.Exit)
{
if (args.Process == null)
{
return;
}
if (args.Process.HasExited)
{
return;
}
if (args.Process.StandardOutput.EndOfStream)
{
return;
}
int readBytes = this.Process.StandardOutput.Read(readBuffer, 0, readBuffer.Length);
args.IntermediateDataStore.Append(readBuffer, 0, readBytes);
this.FireOnDataRead(new String(readBuffer, 0, readBytes));
}
}
catch (ThreadAbortException)
{
if (!args.Process.HasExited)
{
args.Process.Kill();
}
}
}
}
此外,您还需要ProcessOutputReaderWorkerThreadArguments
类,如下所示:
/// <summary>
/// Represents the ProcessOutputReaderWorkerThreadArguments class.
/// </summary>
public class ProcessOutputReaderWorkerThreadArguments
{
/// <summary>
/// Represents the read buffer size,
/// </summary>
private int readBufferSize;
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.
/// </summary>
/// <param name="process">The process.</param>
/// <param name="intermediateDataStore">The intermediate data store.</param>
public ProcessOutputReaderWorkerThreadArguments(Process process, StringBuilder intermediateDataStore)
{
this.ReadBufferSize = 128;
this.Exit = false;
this.Process = process;
this.IntermediateDataStore = intermediateDataStore;
}
/// <summary>
/// Gets or sets a value indicating whether the thread shall exit or not.
/// </summary>
public bool Exit
{
get;
set;
}
/// <summary>
/// Gets or sets the read buffer size in bytes.
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified value is not greather than 0.</exception>
public int ReadBufferSize
{
get
{
return this.readBufferSize;
}
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException("value", "The specified value for \"ReadBufferSize\" must be greater than 0.");
}
this.readBufferSize = value;
}
}
/// <summary>
/// Gets the process.
/// </summary>
public Process Process
{
get;
private set;
}
/// <summary>
/// Gets the intermediate data store.
/// </summary>
public StringBuilder IntermediateDataStore
{
get;
private set;
}
}
ProcessOutputReaderEventArgs
类看起来像这样:
/// <summary>
/// Represents the ProcessOutputReaderEventArgs class.
/// </summary>
public class ProcessOutputReaderEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReaderEventArgs"/> class.
/// </summary>
/// <param name="intermediateDataStore">The reference to the intermediate data store.</param>
/// <param name="newData">The new data that has been read.</param>
public ProcessOutputReaderEventArgs(StringBuilder intermediateDataStore, string newData)
{
this.IntermediateDataStore = intermediateDataStore;
this.NewData = newData;
}
/// <summary>
/// Gets the reference to the intermediate data store.
/// </summary>
public StringBuilder IntermediateDataStore
{
get;
private set;
}
/// <summary>
/// Gets the new data that has been read.
/// </summary>
public string NewData
{
get;
private set;
}
}
答案 1 :(得分:0)
如何实现这一目标的一些示例(注意,代码未经测试且可以改进)
ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();
// Do whatever you want here
// (e.g. sleep or whatever)
por.StopReading();
// Now you have everything that has been read in por.Lines
该课程如下:
public class ProcessOutputReader
{
public ProcessOutputReader(Process process)
{
this.Process = process;
this.Lines = new List<string>();
}
public List<string> Lines
{
get;
private set;
}
public Process Process
{
get;
private set;
}
private Thread ReaderThread
{
get;
set;
}
public void StartReading()
{
if (this.ReaderThread == null)
{
this.ReaderThread = new Thread(new ThreadStart(ReaderWorker));
}
if (!this.ReaderThread.IsAlive)
{
this.ReaderThread.Start();
}
}
public void StopReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
this.ReaderThread.Abort();
this.ReaderThread.Join();
}
}
}
private void ReaderWorker()
{
try
{
while (!this.Process.HasExited)
{
string data = this.Process.StandardOutput.ReadLine();
this.Lines.Add(data);
}
}
catch (ThreadAbortException)
{
if (!this.Process.HasExited)
{
this.Process.Kill();
}
}
}
}