从进程获取实时输出

发布于 2024-12-26 04:07:34 字数 1588 浏览 3 评论 0 原文

我的项目有问题。我想启动一个进程,7z.exe(控制台版本)。 我尝试了三种不同的方法:

  • Process.StandardOutput.ReadToEnd();
  • 接收到的输出数据BeginOutputReadLine
  • StreamWriter

没有任何作用。它总是“等待”过程结束以显示我想要的内容。 我没有任何代码可以放置,只是如果您希望我的代码具有上面列出的内容之一。谢谢。

编辑: 我的代码:

        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.CreateNoWindow = true;
        process.Start();

        this.sr = process.StandardOutput;
        while (!sr.EndOfStream)
        {
            String s = sr.ReadLine();
            if (s != "")
            {
                System.Console.WriteLine(DateTime.Now + " - " + s);
            }
        }

或者

process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(recieve);
process.StartInfo.CreateNoWindow = true;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
public void recieve(object e, DataReceivedEventArgs outLine)
{
    System.Console.WriteLine(DateTime.Now + " - " + outLine.Data);
}

或者

process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
string output = p.StandardOutput.ReadToEnd();
process.WaitForExit();

其中“进程”是我预先制作的进程

好的,我知道为什么它不能正常工作:7z.exe 是错误:它在控制台中显示加载百分比,并且仅在当前文件时才发送信息完成了。例如,在提取中,它工作得很好:)。我将寻找另一种在没有 7z.exe 的情况下使用 7z 函数的方法(也许使用 7za.exe 或某些 DLL)。感谢大家。 为了回答这个问题,OuputDataRecieved 事件工作正常!

I've a problem in my project. I would like to launch a process, 7z.exe (console version).
I've tried three different things:

  • Process.StandardOutput.ReadToEnd();
  • OutputDataReceived & BeginOutputReadLine
  • StreamWriter

Nothing works. It always "wait" for the end of the process to show what i want.
I don't have any code to put, just if you want my code with one of the things listed upthere. Thanks.

Edit:
My code:

        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.CreateNoWindow = true;
        process.Start();

        this.sr = process.StandardOutput;
        while (!sr.EndOfStream)
        {
            String s = sr.ReadLine();
            if (s != "")
            {
                System.Console.WriteLine(DateTime.Now + " - " + s);
            }
        }

Or

process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(recieve);
process.StartInfo.CreateNoWindow = true;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
public void recieve(object e, DataReceivedEventArgs outLine)
{
    System.Console.WriteLine(DateTime.Now + " - " + outLine.Data);
}

Or

process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
string output = p.StandardOutput.ReadToEnd();
process.WaitForExit();

Where "process" is my pre-made Process

Ok i know why it doesn't works properly: 7z.exe is the bug: it display a percent loading in console, and it sends information only when the current file is finished. In extraction for example, it works fine :). I will search for another way to use 7z functions without 7z.exe (maybe with 7za.exe or with some DLL). Thanks to all.
To answer to the question, OuputDataRecieved event works fine !

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

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

发布评论

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

评论(7

孤檠 2025-01-02 04:07:34

看看这个页面,看起来这就是适合您的解决方案: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspxhttp://msdn.microsoft.com/en-us/library /system.diagnostics.process.standardoutput.aspx

[编辑]
这是一个工作示例:

        Process p = new Process();
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.FileName = @"C:\Program Files (x86)\gnuwin32\bin\ls.exe";
        p.StartInfo.Arguments = "-R C:\\";

        p.OutputDataReceived += new DataReceivedEventHandler((s, e) => 
        { 
            Console.WriteLine(e.Data); 
        });
        p.ErrorDataReceived += new DataReceivedEventHandler((s, e) =>
        {
            Console.WriteLine(e.Data);
        });

        p.Start();
        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

顺便说一句,ls -RC:\ 递归地列出 C: 根目录中的所有文件。这些文件很多,我确信当第一个结果出现在屏幕上时它还没有完成。
7zip 有可能在显示输出之前保留它。我不确定你给进程提供了什么参数。

Take a look at this page, it looks this is the solution for you: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspx and http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx

[Edit]
This is a working example:

        Process p = new Process();
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.FileName = @"C:\Program Files (x86)\gnuwin32\bin\ls.exe";
        p.StartInfo.Arguments = "-R C:\\";

        p.OutputDataReceived += new DataReceivedEventHandler((s, e) => 
        { 
            Console.WriteLine(e.Data); 
        });
        p.ErrorDataReceived += new DataReceivedEventHandler((s, e) =>
        {
            Console.WriteLine(e.Data);
        });

        p.Start();
        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

Btw, ls -R C:\ lists all files from the root of C: recursively. These are a lot of files, and I'm sure it isn't done when the first results show up in the screen.
There is a possibility 7zip holds the output before showing it. I'm not sure what params you give to the proces.

香草可樂 2025-01-02 04:07:34

要正确处理输出和/或错误重定向,您还必须重定向输入。
这似乎是您正在启动的外部应用程序运行时的功能/错误,从我到目前为止所看到的情况来看,其他任何地方都没有提到它。

用法示例:

        Process p = new Process(...);

        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardInput = true; // Is a MUST!
        p.EnableRaisingEvents = true;

        p.OutputDataReceived += OutputDataReceived;
        p.ErrorDataReceived += ErrorDataReceived;

        Process.Start();

        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        p.WaitForExit();

        p.OutputDataReceived -= OutputDataReceived;
        p.ErrorDataReceived -= ErrorDataReceived;

...

    void OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        // Process line provided in e.Data
    }

    void ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        // Process line provided in e.Data
    }

To correctly handle output and/or error redirection you must also redirect input.
It seem to be feature/bug in runtime of the external application youre starting and from what I have seen so far, it is not mentioned anywhere else.

Example usage:

        Process p = new Process(...);

        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardInput = true; // Is a MUST!
        p.EnableRaisingEvents = true;

        p.OutputDataReceived += OutputDataReceived;
        p.ErrorDataReceived += ErrorDataReceived;

        Process.Start();

        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        p.WaitForExit();

        p.OutputDataReceived -= OutputDataReceived;
        p.ErrorDataReceived -= ErrorDataReceived;

...

    void OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        // Process line provided in e.Data
    }

    void ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        // Process line provided in e.Data
    }
娇女薄笑 2025-01-02 04:07:34

我不知道是否有人仍在寻找解决方案,但这个问题对我来说已经出现过好几次了,因为我正在 Unity 中编写一个工具来支持某些游戏,并且由于某些系统与单声道的互操作性有限(例如,用于从 Word 中读取文本的 PIA),我经常必须编写特定于操作系统(有时是 Windows,有时是 MacOS)的可执行文件并从 Process.Start() 启动它们。

问题是,当您启动这样的可执行文件时,它将在另一个线程中启动,该线程会阻塞您的主应用程序,从而导致挂起。如果您想在这段时间内向用户提供有用的反馈,而不是各自操作系统召唤出的旋转图标,那么您就完蛋了。使用流不起作用,因为线程在执行完成之前仍处于阻塞状态。

我想到的解决方案(对某些人来说可能有点极端,但我发现对我来说效果很好)是使用套接字和多线程在两个应用程序之间建立可靠的同步通信。当然,这只适用于您同时编写这两个应用程序的情况。如果没有,我想你运气不好。 ...我想看看它是否仅适用于使用传统流方法的多线程,所以如果有人想尝试并在这里发布结果,那就太好了。

无论如何,这是目前对我有用的解决方案:

在主程序或调用应用程序中,我执行以下操作:

/// <summary>
/// Handles the OK button click.
/// </summary>
private void HandleOKButtonClick() {
string executableFolder = "";

#if UNITY_EDITOR
executableFolder = Path.Combine(Application.dataPath, "../../../../build/Include/Executables");
#else
executableFolder = Path.Combine(Application.dataPath, "Include/Executables");
#endif

EstablishSocketServer();

var proc = new Process {
    StartInfo = new ProcessStartInfo {
        FileName = Path.Combine(executableFolder, "WordConverter.exe"),
        Arguments = locationField.value + " " + _ipAddress.ToString() + " " + SOCKET_PORT.ToString(), 
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

proc.Start();

这是我建立套接字服务器的位置:

/// <summary>
/// Establishes a socket server for communication with each chapter build script so we can get progress updates.
/// </summary>
private void EstablishSocketServer() {
    //_dialog.SetMessage("Establishing socket connection for updates. \n");
    TearDownSocketServer();

    Thread currentThread;

    _ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
    _listener = new TcpListener(_ipAddress, SOCKET_PORT);
    _listener.Start();

    UnityEngine.Debug.Log("Server mounted, listening to port " + SOCKET_PORT);

    _builderCommThreads = new List<Thread>();

    for (int i = 0; i < 1; i++) {
        currentThread = new Thread(new ThreadStart(HandleIncomingSocketMessage));
        _builderCommThreads.Add(currentThread);
        currentThread.Start();
    }
}

/// <summary>
/// Tears down socket server.
/// </summary>
private void TearDownSocketServer() {
    _builderCommThreads = null;

    _ipAddress = null;
    _listener = null;
}

这是我的线程套接字处理程序...请注意,您必须创建多个某些情况下有线程;这就是为什么我在那里有 _builderCommThreads 列表(我从其他地方的代码中移植了它,我在其他地方做了类似的事情,但连续调用多个实例):

/// <summary>
/// Handles the incoming socket message.
/// </summary>
private void HandleIncomingSocketMessage() {
    if (_listener == null) return;

    while (true) {
        Socket soc = _listener.AcceptSocket();
        //soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000);
        NetworkStream s = null;
        StreamReader sr = null;
        StreamWriter sw = null;
        bool reading = true;

        if (soc == null) break;

        UnityEngine.Debug.Log("Connected: " + soc.RemoteEndPoint);

        try {
            s = new NetworkStream(soc);
            sr = new StreamReader(s, Encoding.Unicode);
            sw = new StreamWriter(s, Encoding.Unicode);
            sw.AutoFlush = true; // enable automatic flushing

            while (reading == true) {
                string line = sr.ReadLine();

                if (line != null) {
                    //UnityEngine.Debug.Log("SOCKET MESSAGE: " + line);
                    UnityEngine.Debug.Log(line);

                    lock (_threadLock) {
                        // Do stuff with your messages here
                    }
                }
            }

            //
        } catch (Exception e) {
            if (s != null) s.Close();
            if (soc != null) soc.Close();
            UnityEngine.Debug.Log(e.Message);
            //return;
        } finally {

        //
        if (s != null) s.Close();
        if (soc != null) soc.Close();

        UnityEngine.Debug.Log("Disconnected: " + soc.RemoteEndPoint);
        }
    }

    return;
}

当然,您需要在顶部声明一些内容:

private TcpListener _listener = null;
private IPAddress _ipAddress = null;
private List<Thread> _builderCommThreads = null;
private System.Object _threadLock = new System.Object();

...然后在调用的可执行文件中,设置另一端(在本例中我使用了静态,您可以使用您想要的任何内容):

private static TcpClient _client = null;
private static Stream _s = null;
private static StreamReader _sr = null;
private static StreamWriter _sw = null;
private static string _ipAddress = "";
private static int _port = 0;
private static System.Object _threadLock = new System.Object();

/// <summary>
/// Main method.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args) {
    try {
        if (args.Length == 3) {
            _ipAddress = args[1];
            _port = Convert.ToInt32(args[2]);

            EstablishSocketClient();
        }

        // Do stuff here

        if (args.Length == 3) Cleanup();
    } catch (Exception exception) {
        // Handle stuff here
        if (args.Length == 3) Cleanup();
    }
}

/// <summary>
/// Establishes the socket client.
/// </summary>
private static void EstablishSocketClient() {
    _client = new TcpClient(_ipAddress, _port);

    try {
        _s = _client.GetStream();
        _sr = new StreamReader(_s, Encoding.Unicode);
        _sw = new StreamWriter(_s, Encoding.Unicode);
        _sw.AutoFlush = true;
    } catch (Exception e) {
        Cleanup();
    }
}

/// <summary>
/// Clean up this instance.
/// </summary>
private static void Cleanup() {
    _s.Close();
    _client.Close();

    _client = null;
    _s = null;
    _sr = null;
    _sw = null;
}

/// <summary>
/// Logs a message for output.
/// </summary>
/// <param name="message"></param>
private static void Log(string message) {
    if (_sw != null) {
        _sw.WriteLine(message);
    } else {
        Console.Out.WriteLine(message);
    }
}

...我使用它在 Windows 上启动一个命令行工具,该工具使用 PIA 内容来从 Word 中提取文本文档。我在 Unity 中尝试了 PIA .dll,但遇到了与 Mono 的互操作问题。我还在 MacOS 上使用它来调用 shell 脚本,这些脚本以批处理模式启动其他 Unity 实例,并在这些实例中运行编辑器脚本,通过此套接字连接与工具进行对话。这太棒了,因为我现在可以向用户发送反馈、调试、监控和响应流程中的特定步骤,等等。

华泰

I don't know if anyone is still looking for a solution to this, but it has come up several times for me because I'm writing a tool in Unity in support of some games and due to the limited interoperability of certain systems with mono (like PIA for reading text from Word, for example), I often have to write OS-specific (sometimes Windows, sometimes MacOS) executables and launch them from Process.Start().

The problem is, when you launch an executable like this it's going to fire up in another thread that blocks your main app, causing a hang. If you want to provide useful feedback to your users during this time beyond the spinning icons conjured up by your respective OS, then you're kind of screwed. Using a stream won't work because the thread is still blocked until execution finishes.

The solution I've hit on, which might seem extreme for some people but I find works quite well for me, is to use sockets and multithreading to set up reliable synchronous comms between the two apps. Of course, this only works if you are authoring both apps. If not, I think you are out of luck. ... I would like to see if it works with just multithreading using a traditional stream approach, so if someone would like to try that and post the results here that would be great.

Anyway, here's the solution currently working for me:

In the main, or calling app, I do something like this:

/// <summary>
/// Handles the OK button click.
/// </summary>
private void HandleOKButtonClick() {
string executableFolder = "";

#if UNITY_EDITOR
executableFolder = Path.Combine(Application.dataPath, "../../../../build/Include/Executables");
#else
executableFolder = Path.Combine(Application.dataPath, "Include/Executables");
#endif

EstablishSocketServer();

var proc = new Process {
    StartInfo = new ProcessStartInfo {
        FileName = Path.Combine(executableFolder, "WordConverter.exe"),
        Arguments = locationField.value + " " + _ipAddress.ToString() + " " + SOCKET_PORT.ToString(), 
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

proc.Start();

Here's where I establish the socket server:

/// <summary>
/// Establishes a socket server for communication with each chapter build script so we can get progress updates.
/// </summary>
private void EstablishSocketServer() {
    //_dialog.SetMessage("Establishing socket connection for updates. \n");
    TearDownSocketServer();

    Thread currentThread;

    _ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
    _listener = new TcpListener(_ipAddress, SOCKET_PORT);
    _listener.Start();

    UnityEngine.Debug.Log("Server mounted, listening to port " + SOCKET_PORT);

    _builderCommThreads = new List<Thread>();

    for (int i = 0; i < 1; i++) {
        currentThread = new Thread(new ThreadStart(HandleIncomingSocketMessage));
        _builderCommThreads.Add(currentThread);
        currentThread.Start();
    }
}

/// <summary>
/// Tears down socket server.
/// </summary>
private void TearDownSocketServer() {
    _builderCommThreads = null;

    _ipAddress = null;
    _listener = null;
}

Here's my socket handler for the thread... note that you will have to create multiple threads in some cases; that's why I have that _builderCommThreads List in there (I ported it from code elsewhere where I was doing something similar but calling multiple instances in a row):

/// <summary>
/// Handles the incoming socket message.
/// </summary>
private void HandleIncomingSocketMessage() {
    if (_listener == null) return;

    while (true) {
        Socket soc = _listener.AcceptSocket();
        //soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000);
        NetworkStream s = null;
        StreamReader sr = null;
        StreamWriter sw = null;
        bool reading = true;

        if (soc == null) break;

        UnityEngine.Debug.Log("Connected: " + soc.RemoteEndPoint);

        try {
            s = new NetworkStream(soc);
            sr = new StreamReader(s, Encoding.Unicode);
            sw = new StreamWriter(s, Encoding.Unicode);
            sw.AutoFlush = true; // enable automatic flushing

            while (reading == true) {
                string line = sr.ReadLine();

                if (line != null) {
                    //UnityEngine.Debug.Log("SOCKET MESSAGE: " + line);
                    UnityEngine.Debug.Log(line);

                    lock (_threadLock) {
                        // Do stuff with your messages here
                    }
                }
            }

            //
        } catch (Exception e) {
            if (s != null) s.Close();
            if (soc != null) soc.Close();
            UnityEngine.Debug.Log(e.Message);
            //return;
        } finally {

        //
        if (s != null) s.Close();
        if (soc != null) soc.Close();

        UnityEngine.Debug.Log("Disconnected: " + soc.RemoteEndPoint);
        }
    }

    return;
}

Of course, you'll need to declare some stuff up at the top:

private TcpListener _listener = null;
private IPAddress _ipAddress = null;
private List<Thread> _builderCommThreads = null;
private System.Object _threadLock = new System.Object();

...then in the invoked executable, set up the other end (I used statics in this case, you can use what ever you want):

private static TcpClient _client = null;
private static Stream _s = null;
private static StreamReader _sr = null;
private static StreamWriter _sw = null;
private static string _ipAddress = "";
private static int _port = 0;
private static System.Object _threadLock = new System.Object();

/// <summary>
/// Main method.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args) {
    try {
        if (args.Length == 3) {
            _ipAddress = args[1];
            _port = Convert.ToInt32(args[2]);

            EstablishSocketClient();
        }

        // Do stuff here

        if (args.Length == 3) Cleanup();
    } catch (Exception exception) {
        // Handle stuff here
        if (args.Length == 3) Cleanup();
    }
}

/// <summary>
/// Establishes the socket client.
/// </summary>
private static void EstablishSocketClient() {
    _client = new TcpClient(_ipAddress, _port);

    try {
        _s = _client.GetStream();
        _sr = new StreamReader(_s, Encoding.Unicode);
        _sw = new StreamWriter(_s, Encoding.Unicode);
        _sw.AutoFlush = true;
    } catch (Exception e) {
        Cleanup();
    }
}

/// <summary>
/// Clean up this instance.
/// </summary>
private static void Cleanup() {
    _s.Close();
    _client.Close();

    _client = null;
    _s = null;
    _sr = null;
    _sw = null;
}

/// <summary>
/// Logs a message for output.
/// </summary>
/// <param name="message"></param>
private static void Log(string message) {
    if (_sw != null) {
        _sw.WriteLine(message);
    } else {
        Console.Out.WriteLine(message);
    }
}

...I'm using this to launch a command line tool on Windows that uses the PIA stuff to pull text out of a Word doc. I tried PIA the .dlls in Unity, but ran into interop issues with mono. I'm also using it on MacOS to invoke shell scripts that launch additional Unity instances in batchmode and run editor scripts in those instances that talk back to the tool over this socket connection. It's great, because I can now send feedback to the user, debug, monitor and respond to specific steps in the process, et cetera, et cetera.

HTH

深巷少女 2025-01-02 04:07:34

该问题是由调用 引起的Process.WaitForExit方法。根据文档,它的作用是:

设置等待关联进程退出的时间段,
阻塞当前线程执行,直到时间过去
或者进程已经退出。 为避免阻塞当前线程,请使用
退出事件

因此,为了防止线程阻塞直到进程退出,请连接 Process 对象的Process.Exited事件处理程序,如下所示。仅当 EnableRaisingEvents 属性的值为 true 时,Exited 事件才会发生。

    process.EnableRaisingEvents = true;
    process.Exited += Proc_Exited;


    private void Proc_Exited(object sender, EventArgs e)
    {
        // Code to handle process exit
    }

通过这种方式,您将能够在进程仍在运行时通过 Process.OutputDataReceived 事件 就像您当前所做的那样。 (PS - 该事件页面上的代码示例也犯了使用 Process.WaitForExit 的错误。)

另一个注意事项是,您需要确保在您的 Exited 方法触发之前您的 Process 对象没有被清理。如果您的进程是在 using 语句中初始化的,这可能是一个问题。

The problem is caused by calling the Process.WaitForExit method. What this does, according to the documentation, is:

Sets the period of time to wait for the associated process to exit,
and blocks the current thread of execution until the time has elapsed
or the process has exited. To avoid blocking the current thread, use
the Exited event
.

So, to prevent the thread blocking until the process has exited, wire up the Process.Exited event handler of the Process object, as below. The Exited event can occur only if the value of the EnableRaisingEvents property is true.

    process.EnableRaisingEvents = true;
    process.Exited += Proc_Exited;


    private void Proc_Exited(object sender, EventArgs e)
    {
        // Code to handle process exit
    }

Done this way, you will be able to get the output of your process, while it is still running, via the Process.OutputDataReceived event as you currently do. (PS - the code example on that event page also makes the mistake of using Process.WaitForExit.)

Another note is that you need to ensure your Process object is not cleaned up before your Exited method can fire. If your Process is initialized in a using statement, this might be a problem.

物价感观 2025-01-02 04:07:34

我已经使用了描述的 CmdProcessor 类 这里有几个取得了巨大成功的项目。乍一看有点令人畏惧,但非常容易使用。

I have used the CmdProcessor class described here on several projects with much success. It looks a bit daunting at first but is very easy to use.

很糊涂小朋友 2025-01-02 04:07:34

Windows 以不同的方式对待管道和控制台。管道是缓冲的,控制台不是。 RedirectStandardOutput 连接管道。只有两种解决方案。

  1. 更改控制台应用程序以在每次写入后刷新其缓冲区
  2. 编写一个垫片以根据 https://www.codeproject.com/Articles/16163/Real-Time-Console-Output-Redirection

请注意,RTConsole 不处理STDERR 也遇到同样的问题。

感谢 https://stackoverflow.com/users/4139809/jeremy-lakeman 与我分享此信息与另一个问题的关系。

Windows treats pipes and consoles differently. Pipes are buffered, consoles are not. RedirectStandardOutput connects a pipe. There are only two solutions.

  1. Change the console app to flush its buffer after every write
  2. Write a shim to fake a console per https://www.codeproject.com/Articles/16163/Real-Time-Console-Output-Redirection

Note that RTConsole does not handle STDERR which suffers the same problem.

Thanks to https://stackoverflow.com/users/4139809/jeremy-lakeman for sharing this information with me in relation to another question.

冷情妓 2025-01-02 04:07:34

试试这个。

        Process notePad = new Process();

        notePad.StartInfo.FileName = "7z.exe";
        notePad.StartInfo.RedirectStandardOutput = true;
        notePad.StartInfo.UseShellExecute = false;

        notePad.Start();
        StreamReader s = notePad.StandardOutput;



        String output= s.ReadToEnd();


        notePad.WaitForExit();

让上面的内容在一个线程中。

现在,为了将输出更新到 UI,您可以使用带有两行的 timer

  Console.Clear();
  Console.WriteLine(output);

这可能会帮助您

Try this.

        Process notePad = new Process();

        notePad.StartInfo.FileName = "7z.exe";
        notePad.StartInfo.RedirectStandardOutput = true;
        notePad.StartInfo.UseShellExecute = false;

        notePad.Start();
        StreamReader s = notePad.StandardOutput;



        String output= s.ReadToEnd();


        notePad.WaitForExit();

Let the above be in a thread.

Now for updating the output to UI,you can use a timer with two lines

  Console.Clear();
  Console.WriteLine(output);

This may help you

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