确定控制台输出结束
Determining end of console output
我在我的应用程序中收到控制台输出。我使用 here 中的代码(公认的解决方案)。
但是我从来没有在 OutputDataReceived 中得到 null。相反,我在输出末尾有 String.Empty 。
使用 String.NullOrEmpty 而不是仅与 null 进行比较是否正确?
static void Main(string[] args)
{
var command = @"wmic cpu get loadpercentage";
using (Process process = new Process())
{
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardError = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
process.OutputDataReceived += (sndr, a) =>
{
if (a.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(a.Data);
}
};
process.ErrorDataReceived += (sndr, a) =>
{
if (a.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(a.Data);
}
};
process.Start();
process.BeginOutputReadLine();
outputWaitHandle.WaitOne();
string path = "Test.txt";
using (StreamWriter sw = File.Exists(path) ? File.AppendText(path) : File.CreateText(path))
{
sw.WriteLine(String.Format("{0}, {1}", DateTime.Now, output));
}
}
}
}
更新: 多行输出好像不行。问题是为什么 a.Data
中没有空值
标准输出流仅在进程本身终止时终止。注意这里,"process"表示进程运行宁cmd.exe
。该进程可以启动 other 个进程,但它们有自己的标准输出流,虽然这些进程的标准输出将在它们自己终止时终止,但 none 会影响父 cmd.exe
进程的标准输出。
如果您想通过模拟用户对 cmd.exe
的输入来 运行 一个 运行 包含各种其他进程的进程,那么您还必须模拟可以识别的用户交互并响应正在执行的最终命令。
想象一下自己处于真实用户的位置,并考虑他们如何处理这种情况。当他们在命令提示符 window 中执行命令时,window 会在命令完成后关闭吗?没有。他们是否收到任何指示命令已完成的指示?有点。首先,他们大概期望命令的输出符合某种特定格式,其中通常会包含一些指示命令已完成的指示符。其次,命令提示符 window 将显示一个新的提示符(即短语 "command-prompt" 中的 "prompt")。
请注意,恶意命令可以找出当前提示的样子并伪造它。但这是不寻常的,并且大概您对发出的命令有足够的控制权来避免这种情况。因此,一种方法是在输出发生时简单地对其进行处理,并检测命令完成时出现的新提示。
如果这看起来不够可靠,那么您将不得不单独处理每个命令,解释命令的输出并仅从该输出中的内容识别该命令何时到达其输出的末尾。
最后请注意,您实际上可以使用 Process
class 自己执行命令。你不需要 cmd.exe
来做到这一点。而且,如果您自己将每个命令作为一个单独的进程执行,那么您 do 最终会通过每个进程的标准输出流结束收到进程终止通知。
我在我的应用程序中收到控制台输出。我使用 here 中的代码(公认的解决方案)。 但是我从来没有在 OutputDataReceived 中得到 null。相反,我在输出末尾有 String.Empty 。 使用 String.NullOrEmpty 而不是仅与 null 进行比较是否正确?
static void Main(string[] args)
{
var command = @"wmic cpu get loadpercentage";
using (Process process = new Process())
{
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardError = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
process.OutputDataReceived += (sndr, a) =>
{
if (a.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(a.Data);
}
};
process.ErrorDataReceived += (sndr, a) =>
{
if (a.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(a.Data);
}
};
process.Start();
process.BeginOutputReadLine();
outputWaitHandle.WaitOne();
string path = "Test.txt";
using (StreamWriter sw = File.Exists(path) ? File.AppendText(path) : File.CreateText(path))
{
sw.WriteLine(String.Format("{0}, {1}", DateTime.Now, output));
}
}
}
}
更新: 多行输出好像不行。问题是为什么 a.Data
中没有空值标准输出流仅在进程本身终止时终止。注意这里,"process"表示进程运行宁cmd.exe
。该进程可以启动 other 个进程,但它们有自己的标准输出流,虽然这些进程的标准输出将在它们自己终止时终止,但 none 会影响父 cmd.exe
进程的标准输出。
如果您想通过模拟用户对 cmd.exe
的输入来 运行 一个 运行 包含各种其他进程的进程,那么您还必须模拟可以识别的用户交互并响应正在执行的最终命令。
想象一下自己处于真实用户的位置,并考虑他们如何处理这种情况。当他们在命令提示符 window 中执行命令时,window 会在命令完成后关闭吗?没有。他们是否收到任何指示命令已完成的指示?有点。首先,他们大概期望命令的输出符合某种特定格式,其中通常会包含一些指示命令已完成的指示符。其次,命令提示符 window 将显示一个新的提示符(即短语 "command-prompt" 中的 "prompt")。
请注意,恶意命令可以找出当前提示的样子并伪造它。但这是不寻常的,并且大概您对发出的命令有足够的控制权来避免这种情况。因此,一种方法是在输出发生时简单地对其进行处理,并检测命令完成时出现的新提示。
如果这看起来不够可靠,那么您将不得不单独处理每个命令,解释命令的输出并仅从该输出中的内容识别该命令何时到达其输出的末尾。
最后请注意,您实际上可以使用 Process
class 自己执行命令。你不需要 cmd.exe
来做到这一点。而且,如果您自己将每个命令作为一个单独的进程执行,那么您 do 最终会通过每个进程的标准输出流结束收到进程终止通知。