首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Diagnostic.Process合并StandardOutput和StandardErrorOutput

Diagnostic.Process合并StandardOutput和StandardErrorOutput
EN

Stack Overflow用户
提问于 2015-04-23 16:39:45
回答 1查看 560关注 0票数 1

我使用Process类从.NET程序运行cmd.exe,并传入各种命令来执行程序,例如ipconfig,netstat等。问题是有时这些程序输出错误文本,这些文本被发送到StandardError,但在标准输出过程中无法确切知道错误被打印到哪里。我得到的只是单独的错误消息。有没有可能将StandardOutput和StandardError合并到一个同步流中,这样我就可以获得所有的数据?如果不是,那么我如何组织来自两个不同流的输出,使其按正确的顺序排列?

EN

回答 1

Stack Overflow用户

发布于 2015-04-23 20:24:44

井。我猜您不能真的期望STDOUT和STDERR按照它们输出的确切顺序出现。这是因为在系统级,STDOUT和STDERR分别有自己的缓冲区。你可以想象这样的情况-

(1)当'command‘首先写入STDOUT时,可能不会立即刷新缓冲区。

(2)然后'command‘写入STDERR,但是这次STDERR的缓冲区可能会被刷新。

在这种情况下,虽然(1)在前面,但我们最终得到的是(2)在前面。

希望下面的代码片段能有所帮助-

(改进代码)

代码语言:javascript
复制
    class OutputContext
    {
        public const int BufferSize = 1024;

        public bool IsEof { get; set; }
        public bool IsWaiting { get; set; }
        public byte[] Buffer { get; set; }
        public StreamReader Reader { get; set; }
        public object Tag { get; set; }

        public OutputContext(StreamReader r, object tag)
        {
            IsEof = false;
            IsWaiting = false;
            Buffer = new byte[BufferSize];
            Reader = r;
            Tag = tag;
        }
    }

    Process proc;

    void Callback(IAsyncResult ar)
    {
        lock (ar.AsyncState)
        {
            OutputContext ctx = ar.AsyncState as OutputContext;
            int c = ctx.Reader.BaseStream.EndRead(ar);
            ctx.IsWaiting = false;

            if (c == 0)
            {
                ctx.IsEof = true;
                return;
            }

            string content = Encoding.UTF8.GetString(ctx.Buffer, 0, c);
            Console.Write(content);
            Console.Out.Flush();

        }
    }

    void RedirectOutput(OutputContext ctx)
    {
        lock (ctx)
        {
            if (ctx.IsEof)
            {
                return;
            }

            if (ctx.IsWaiting)
            {
                return;
            }

            ctx.IsWaiting = true;
            IAsyncResult ar = ctx.Reader.BaseStream.BeginRead(ctx.Buffer, 0, 
                OutputContext.BufferSize, Callback, ctx);
        }
    }

    void Run(string yourprog, string yourargs)
    {
        // If this is a GUI app, this shall not be run on the UI thread.
        // Spin a new thread to handle it and wait for the thread to complete.
        // And you can always accept the input as long as the UI thread is not
        // blocked, and redirect the input to the target proc's stdin asycly.

        proc = new Process();
        proc.StartInfo.CreateNoWindow = true;
        proc.StartInfo.FileName = yourprog;
        proc.StartInfo.Arguments = yourargs;
        proc.StartInfo.UseShellExecute = false;

        proc.StartInfo.RedirectStandardOutput = true;
        proc.StartInfo.RedirectStandardError = true;
        proc.StartInfo.RedirectStandardInput = true;

        proc.Start();

        OutputContext stdoutCtx = new OutputContext(proc.StandardOutput, "STDOUT");
        OutputContext stderrCtx = new OutputContext(proc.StandardError, "STDERR");

        while (!stdoutCtx.IsEof && !stderrCtx.IsEof)
        {
            RedirectOutput(stdoutCtx);
            RedirectOutput(stderrCtx);
        }

        proc.WaitForExit();
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29818035

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档