c# - 从进程中读取,StreamReader.Peek() 未按预期工作

标签 c# process stream

参见下面的类,我用它来读取添加到它的任何进程的输出。目前我正在启动一个 Jar,它充当 C# 应用程序和 JMS 消息传递代理之间的 channel 适配器。唯一的问题是,当从进程的 StandardOutput 读取时,线程会阻塞 reader.Peek() 调用。

经过一些调试后,我发现只有当没有输出写入进程的 StandardOutput 流时才会发生这种情况。我已经对即时窗口进行了一些尝试,以确定是否可以找到一种方法来确定基础流是否为空。但到目前为止,对 Stream.CanReadFileStream.Length 等属性的所有调用都会抛出 InvalidOperationExceptions 或返回无法用于检查此条件的输出.

此外,我还尝试使用 OutputDataReceivedErrorDataReceived 事件,但出于某种原因,它们似乎从未触发。

所以我的问题是;有没有什么方法可以用来在进程输出可用时清晰地读取它?

读取输出的类:

namespace ReparatieSysteem.Lib
{
    internal delegate void NewOutputLineEvent(Process process, int port, string line);

    class ProcessListener
    {
        private static readonly Dictionary<int, Process> processes;
        private static readonly Thread thread;

        static ProcessListener()
        {
            processes = new Dictionary<int, Process>();
            thread = new Thread(RunThread);
            thread.Start();
        }

        private static void PollProcesses()
        {
            foreach (var item in processes.Where(p => p.Value.HasExited).ToList())
            {
                processes.Remove(item.Key);
            }

            foreach (var item in processes)
            {
                SendLines(item.Value, item.Key, ReadReader(item.Value.StandardError));
                SendLines(item.Value, item.Key, ReadReader(item.Value.StandardOutput));
            }

        }

        private static void SendLines(Process process, int port, IEnumerable<String> lines)
        {
            foreach(var line in lines)
            {
                if (OnNewOutput != null)
                {
                    OnNewOutput(process, port, line);
                }
            }
        }

        private static IEnumerable<string> ReadReader(StreamReader reader)
        {
            while (reader.Peek() >= 0)
            {
                yield return reader.ReadLine();
            }
        }

        private static void RunThread()
        {
            while(true)
            {
                if (processes.Count > 0)
                {
                    PollProcesses();
                }

                Thread.Sleep(200);
            }
        }

        public static void AddProcess(int port, Process process)
        {
            processes.Add(port, process);
        }

        public static event NewOutputLineEvent OnNewOutput;
    }
}

创建进程的代码:

var procStartInfo = new ProcessStartInfo("java", 
            string.Format("-jar {0} {1} {2} {3}", JarPath, ConnectionName, _listenQueue, _listenPort))
        {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        _brokerProcess = new Process { StartInfo = procStartInfo };

        _brokerProcess.Start();

        ShutdownListener.OnApplicationQuit += _brokerProcess.Kill;

        ProcessListener.AddProcess(_listenPort, _brokerProcess);

最佳答案

这似乎是 StreamReader 实现中的一个已知错误,如 this answer 中所建议的那样.您的解决方法是使用异步流方法,例如 StreamReader.ReadAsyncStreamReader.ReadLineAsync .

关于c# - 从进程中读取,StreamReader.Peek() 未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24252408/

相关文章:

c# - 如何创建简单的 C# 全双工 TCP/IP 流套接字连接?

c++ - 内存地址会改变吗?如何动态找到它们?

java - 如何避免简单代理服务器中的连接拒绝?

tcp - 哪种方法更适合在两个进程、本地 TCP/IP 连接或进程间通信之间发送图像流?

c# - 创建一个不停止代码的 MessageBox?

c# - 在 asp.net core/kestrel 中记录异常

c# - 具有只读属性的数据绑定(bind)

iphone - 从 pid 获取优先级和正常运行时间? ( iOS )

c# - 计算 Windows 进程的 CPU 使用率?

delphi - TResourceStream 的进度条 (Delphi)