简体   繁体   English

从进程读取,StreamReader.Peek()无法按预期工作

[英]Reading from a process, StreamReader.Peek() not working as expected

See the following class below, I use it to read the output from any of the processes that are added to it. 请参阅下面的以下类,我用它来读取添加到它的任何进程的输出。 At the moment I'm starting up a Jar that acts as a channel adapter between the C# application and a JMS messaging broker. 目前我正在启动一个Jar,它充当C#应用程序和JMS消息代理之间的通道适配器。 The only problem is, that when reading from the StandardOutput of the process the thread blocks on the reader.Peek() call. 唯一的问题是,当从进程的StandardOutput读取时,线程会在reader.Peek()调用上reader.Peek()

After some debugging I found out that this only happens if no output has been written to the StandardOutput stream of the process. 经过一些调试后,我发现只有在没有输出写入进程的StandardOutput流时才会发生这种情况。 I've played around a bit with the immediate window to figure out if I can find a way to determine whether the underlying stream is empty. 我已经玩了一下立即窗口,以确定我是否能找到一种方法来确定底层流是否为空。 But so far all calls to properties like Stream.CanRead or FileStream.Length throw InvalidOperationExceptions or return output that cannot be used to check for this condition. 但到目前为止,对Stream.CanReadFileStream.Length等属性的所有调用Stream.CanRead抛出InvalidOperationExceptions或返回不能用于检查此情况的输出。

Furthermore, I also tried using the OutputDataReceived and ErrorDataReceived events, but for some reason they never seem to fire. 此外,我还尝试使用OutputDataReceivedErrorDataReceived事件,但由于某种原因,它们似乎永远不会触发。

So my question is; 所以我的问题是; is there any way that can be used to cleanly read the output from the processes as it becomes available? 有没有什么方法可以用来干净地读取进程的输出?

The class in which the output is read: 读取输出的类:

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;
    }
}

The code that creates the process: 创建进程的代码:

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);

Seems that this is a known bug in StreamReader implementation, as suggested in this answer . 似乎这是StreamReader实现中的一个已知错误,正如本答案中所建议的那样。 The workaround in your case is to use asynchronous stream methods like StreamReader.ReadAsync or StreamReader.ReadLineAsync . 您的情况下的解决方法是使用StreamReader.ReadAsyncStreamReader.ReadLineAsync等异步流方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM