当收到任何字符串而不是在行尾时,System.Diagnostic 是否可以重定向输出?

发布于 2024-12-10 19:32:59 字数 549 浏览 0 评论 0原文

是否可以在..发生时而不是在行尾接收 System.Diagnostic.Process 的输出? 目前,

    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
    psi.UseShellExecute = false;

    reg = System.Diagnostics.Process.Start(psi);

    reg.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
    reg.BeginOutputReadLine();  

如您所见,对 BeginOutputReadLine 的调用允许我仅在找到结束行时读取(重定向的)输出。 是否存在相同的方法,但“当进程发送任何字符到输出时”调用委托?

谢谢

Is it possible to receive the output from System.Diagnostic.Process when..occur and not at the end of line ?
At the moment, i have

    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
    psi.UseShellExecute = false;

    reg = System.Diagnostics.Process.Start(psi);

    reg.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
    reg.BeginOutputReadLine();  

As you can see, a call to BeginOutputReadLine allow me to read the (redirected) output only when an end line is found.
Does exists the same method but that call the delegate "when the process send any char to output" ?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不奢求什么 2024-12-17 19:32:59

简短的回答:不,Process 上有这样的方法可以满足您的需要。

长答案:是的,您似乎确实能够做到这一点,但这需要您做更多的工作。

(不过,正如 Hans Passant 所说,提前刷新还取决于其他进程。如果不这样做,则没有任何帮助。)

方法 1(困难)

BeginOutputReadLine< /strong> 似乎围绕实际的底层 Stream.BeginRead 方法创建一个同步包装器,确保它缓冲足够的数据并调用您的 OutputDataReceived 处理程序。 (实际上,它做了相当多的工作来为您提供完整的行,而不是块,更不用说同步事件调度了,从我用 ILSpy 看到的。)

所以您可能会尝试调用 StandardOutput.BaseStream。直接使用 BeginRead 方法,完全跳过 OutputDataReceivedBeginOutputReadLine,这样您就可以在收到块时接收它们。

不幸的是,这确实意味着您需要自己进行编码(因为 Streams 处理字节而不是字符,但 StandardOutput.CurrentEncoding 提供了大部分支持),您需要执行所有操作自己异步读取(Stream.BeginRead 不是一个令人愉快的 API),并且您需要自己处理同步。

很有趣(也有很多出错的机会)。

方法 2(更简单),几乎异步

您还可以使用 StandardOutput.ReadStandardOutput 同步读取。如果你不想阻塞,你可以分出另一个线程或使用 TaskFactory.StartNew

var readTask = TaskFactory.StartNew(() => {
    try
    {
        while ((int c = process.StandardOutput.Read()) != -1) 
        {
           ...
        }
    }
    catch
    {
        // don't want to kill the process if something goes wrong above;
        // uncaught exceptions on background threads do that.
    }
});

然后在你想确保读取完成时,你说

readTask.Wait();

Short answer: no, there are is such method on Process that does what you need.

Long answer: yes, you do appear to be able to do this, but it will take you a lot more work.

(Still, as Hans Passant says, it's also up to the other process to flush early. If it doesn't, nothing is going to help you.)

Method 1 (hard)

BeginOutputReadLine appears to create a synchronized wrapper around the actual underlying Stream.BeginRead method, ensuring it buffers enough data and calls your OutputDataReceived handler. (And it actually does quite a bit of work to give you complete lines, not chunks, not to mention the synchronized event dispatching, from what I can see with ILSpy.)

So you might try to call the StandardOutput.BaseStream.BeginRead method directly, skipping OutputDataReceived and BeginOutputReadLine entirely, so you can receive the chunks as they are received.

Unfortunately, that does mean that you need to do the encoding yourself (as Streams deal with bytes not chars, but the StandardOutput.CurrentEncoding provides the bulk of this support), you'll need to do all the async reading yourself (Stream.BeginRead is not a pleasant API to work against), and you'll need to handle the synchronizing yourself.

Lots of fun (and lots of chances to get something wrong).

Method 2 (easier), almost async

You can also read from the StandardOutput synchronously using StandardOutput.Read. If you do not want to block, you could spin off another thread or use TaskFactory.StartNew:

var readTask = TaskFactory.StartNew(() => {
    try
    {
        while ((int c = process.StandardOutput.Read()) != -1) 
        {
           ...
        }
    }
    catch
    {
        // don't want to kill the process if something goes wrong above;
        // uncaught exceptions on background threads do that.
    }
});

And then at the point you want to be sure the reading is done, you say

readTask.Wait();
春夜浅 2024-12-17 19:32:59

异步方法/事件似乎不允许您从输出中读取单个字符(只有完整的行,如方法名称所示)。

以下代码以同步方式执行您想要的操作:

class Program
{
    public static bool Exit = false;
    static void Main(string[] args)
    {
        var p = new Process
                    {
                        StartInfo =
                            {
                                FileName = @"program-not-outputting-newlines",
                                Arguments = "test",
                                UseShellExecute = false,
                                RedirectStandardOutput = true
                            },
                        EnableRaisingEvents = true
                    };
        p.Start();
        var s = p.StandardOutput;
        p.Exited += (sender, e) => Exit = true;

        while(!Exit)
        {
            Console.Write((char) s.Read());
        }
        Console.Read();
    }
}

对 s.Read() 的调用似乎会阻止当前线程(即使有一个 ReadBlock() 版本 - 文档编写者可能误解了),所以您可能想要在一个单独的线程中进行操作,并执行一些您自己的消息传递/事件引发以使其异步。

我测试的程序是一个简单的循环,以随机间隔输出从 0 到 10 的整数,中间没有换行符,并且每次写入都会调用 Console.Out.Flush。

It would seem that the asynchronous methods/events don't allow you to read single characters from the output (Only complete lines, as the method names suggest).

The following code does what you want, but in a synchronous way:

class Program
{
    public static bool Exit = false;
    static void Main(string[] args)
    {
        var p = new Process
                    {
                        StartInfo =
                            {
                                FileName = @"program-not-outputting-newlines",
                                Arguments = "test",
                                UseShellExecute = false,
                                RedirectStandardOutput = true
                            },
                        EnableRaisingEvents = true
                    };
        p.Start();
        var s = p.StandardOutput;
        p.Exited += (sender, e) => Exit = true;

        while(!Exit)
        {
            Console.Write((char) s.Read());
        }
        Console.Read();
    }
}

The call to s.Read() seems to block the current thread (Even though there is a ReadBlock() version of it -- the docwriter probably misunderstood), so you might want to make that in a seperate thread and do some message passing/eventraising of your own to make it asynchronous.

The program I tested with was a simple loop outputting integers from 0 to 10 with random intervals, without newlines in between, and calls to Console.Out.Flush for every write.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文