Process.start:如何获得输出?

sti*_*ghy 281 .net c# mono process.start

我想从我的Mono/.NET应用程序运行外部命令行程序.例如,我想运行mencoder.可能吗:

  1. 要获取命令行shell输出,并将其写在我的文本框中?
  2. 要获得数值以显示时间流逝的进度条?

Fer*_*cio 427

适当地创建Process对象集时StartInfo:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};
Run Code Online (Sandbox Code Playgroud)

然后开始这个过程并从中读取:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}
Run Code Online (Sandbox Code Playgroud)

您可以使用int.Parse()int.TryParse()将字符串转换为数字值.如果您读取的字符串中包含无效的数字字符,则可能必须先进行一些字符串操作.

  • 我想知道你如何处理StandardError?BTW我真的很喜欢这个代码片段!干净整洁. (3认同)
  • 谢谢,但我想我不清楚:我应该添加另一个循环吗? (2认同)
  • 读取直到进程本身终止而不是等待流结束是否更稳健? (2认同)
  • @Gusdor - 我不这么认为。当进程终止时,其流将自动关闭。此外,进程可能会在终止之前很久就关闭其流。 (2认同)

T30*_*T30 228

您可以同步异步处理输出.

1:同步示例

static void runCommand()
{
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.Start();
    //* Read the output (or the error)
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    string err = process.StandardError.ReadToEnd();
    Console.WriteLine(err);
    process.WaitForExit();
}
Run Code Online (Sandbox Code Playgroud)

请注意,最好同时处理输出错误:它们必须单独处理.

(*)对于某些命令(此处StartInfo.Arguments),您必须添加/c 指令,否则进程会冻结WaitForExit().

2:异步示例

static void runCommand() 
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set your output and error (asynchronous) handlers
    process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process and handlers
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}
Run Code Online (Sandbox Code Playgroud)

如果您不需要对输出执行复杂操作,则可以绕过OutputHandler方法,只需直接添加处理程序:

//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
Run Code Online (Sandbox Code Playgroud)

  • **注意:**您的第一个(同步)方法不正确!您不应该同时读取StandardOutput和StandardError!它会导致死锁.至少其中一个必须是异步的. (5认同)
  • Process.WaitForExit()是线程阻塞,因此是同步的.不是答案,但我想我可能会加上这个.添加process.EnableRaisingEvents = true并使Exited事件完全异步. (5认同)
  • 得爱异步!我能够在VB.net中使用这段代码(稍加抄写) (2认同)
  • 你缺少一个处置。 (2认同)

cub*_*man 11

好吧,对于任何想要读错误和输出的人来说,但是在其他答案(比如我)中提供的任何解决方案都会遇到死锁,这是我在阅读标准输出属性的MSDN解释后构建的解决方案.

答案基于T30的代码:

static void runCommand()
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set ONLY ONE handler here.
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process
    process.Start();
    //* Read one element asynchronously
    process.BeginErrorReadLine();
    //* Read the other one synchronously
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}
Run Code Online (Sandbox Code Playgroud)


dri*_*iis 7

执行此操作的标准.NET方法是从Process的StandardOutput流中读取.链接的MSDN文档中有一个示例.类似地,您可以从StandardError读取,并写入StandardInput.


bas*_*rat 6

  1. 可以获得进程的命令行 shell 输出,如下所述:http : //www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. 这取决于mencoder。如果它在命令行上输出此状态,则是 :)


sha*_*m02 5

您可以使用共享内存为 2 个进程进行通信,请查看 MemoryMappedFile

您将主要mmf使用“using”语句在父进程中创建一个内存映射文件,然后创建第二个进程直到它终止并将结果写入mmfusing BinaryWriter,然后从mmfusing 父进程读取结果,您也可以mmf使用命令行参数或硬编码传递名称。

确保在父进程中使用映射文件时,您让子进程在父进程中释放映射文件之前将结果写入映射文件

示例:父进程

    private static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("memfile", 128))
        {
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(512);
            }

            Console.WriteLine("Starting the child process");
            // Command line args are separated by a space
            Process p = Process.Start("ChildProcess.exe", "memfile");

            Console.WriteLine("Waiting child to die");

            p.WaitForExit();
            Console.WriteLine("Child died");

            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("Result:" + reader.ReadInt32());
            }
        }
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)

子进程

    private static void Main(string[] args)
    {
        Console.WriteLine("Child process started");
        string mmfName = args[0];

        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(mmfName))
        {
            int readValue;
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("child reading: " + (readValue = reader.ReadInt32()));
            }
            using (MemoryMappedViewStream input = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(input);
                writer.Write(readValue * 2);
            }
        }

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)

要使用此示例,您需要创建一个包含 2 个项目的解决方案,然后从 %childDir%/bin/debug 获取子进程的构建结果并将其复制到 %parentDirectory%/bin/debug 然后运行父项目

childDir并且parentDirectory是你的项目在电脑上的文件夹名称祝你好运:)