gpt4 book ai didi

C# : Redirect console application output : How to flush the output?

转载 作者:太空狗 更新时间:2023-10-29 22:25:06 31 4
gpt4 key购买 nike

我正在生成外部控制台应用程序并使用异步输出重定向。
as shown in this SO post

我的问题是,在我收到 OutputDataReceived 事件通知之前,生成的进程似乎需要产生一定数量的输出。

我想尽快收到 OutputDataReceived 事件。

我有一个基本的重定向应用程序,以下是一些观察结果:
1. 当我调用一个简单的 'while(true) print("X");' 时控制台应用程序 (C#) 我立即收到输出事件。2. 当我调用 3d 派对应用程序时,我试图从命令行包装我看到逐行输出。
3. 当我从我的基本包装程序调用 3d 派对应用程序时(请参阅 1)- 输出以 block 的形式出现(大约一页大小)。

该应用内部发生了什么?

仅供引用:有问题的应用程序是“USBee DX Data Exctarctor(异步总线)v1.0”。

最佳答案

我做了更多研究并修复了 Microsoft Process 类。但由于我的上一个答案被无故删除,我不得不创建一个新的。

所以拿这个例子...

创建一个 Windows 应用程序并在主窗体上粘贴一个富文本框,然后将其添加到窗体加载...

        Process p = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "cmd.exe",
CreateNoWindow = true,
UseShellExecute = false,
ErrorDialog = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
},
EnableRaisingEvents = true,
SynchronizingObject = this
};

p.OutputDataReceived += (s, ea) => this.richTextBox1.AppendText(ea.Data);

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

这将输出类似这样的内容...

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.

最后一行未触发 OutputDataReceived 事件。在一些 ILSpying 之后,这似乎是故意的,因为最后一行没有以 crlf 结尾,它假定有更多的提交并将其附加到下一个事件的开头。

为了更正这个问题,我为 Process 类编写了一个包装器,并从中取出了一些必需的内部类,以便它们都能正常工作。这是 FixedProcess 类...

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Threading;

namespace System.Diagnostics
{
internal delegate void UserCallBack(string data);
public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);

public class FixedProcess : Process
{
internal AsyncStreamReader output;
internal AsyncStreamReader error;
public event DataReceivedEventHandler OutputDataReceived;
public event DataReceivedEventHandler ErrorDataReceived;

public new void BeginOutputReadLine()
{
Stream baseStream = StandardOutput.BaseStream;
this.output = new AsyncStreamReader(this, baseStream, new UserCallBack(this.FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
this.output.BeginReadLine();
}

public void BeginErrorReadLine()
{
Stream baseStream = StandardError.BaseStream;
this.error = new AsyncStreamReader(this, baseStream, new UserCallBack(this.FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
this.error.BeginReadLine();
}

internal void FixedOutputReadNotifyUser(string data)
{
DataReceivedEventHandler outputDataReceived = this.OutputDataReceived;
if (outputDataReceived != null)
{
DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
{
this.SynchronizingObject.Invoke(outputDataReceived, new object[]
{
this,
dataReceivedEventArgs
});
return;
}
outputDataReceived(this, dataReceivedEventArgs);
}
}

internal void FixedErrorReadNotifyUser(string data)
{
DataReceivedEventHandler errorDataReceived = this.ErrorDataReceived;
if (errorDataReceived != null)
{
DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
{
this.SynchronizingObject.Invoke(errorDataReceived, new object[]
{
this,
dataReceivedEventArgs
});
return;
}
errorDataReceived(this, dataReceivedEventArgs);
}
}
}

internal class AsyncStreamReader : IDisposable
{
internal const int DefaultBufferSize = 1024;
private const int MinBufferSize = 128;
private Stream stream;
private Encoding encoding;
private Decoder decoder;
private byte[] byteBuffer;
private char[] charBuffer;
private int _maxCharsPerBuffer;
private Process process;
private UserCallBack userCallBack;
private bool cancelOperation;
private ManualResetEvent eofEvent;
private Queue messageQueue;
private StringBuilder sb;
private bool bLastCarriageReturn;
public virtual Encoding CurrentEncoding
{
get
{
return this.encoding;
}
}
public virtual Stream BaseStream
{
get
{
return this.stream;
}
}
internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding)
: this(process, stream, callback, encoding, 1024)
{
}
internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
{
this.Init(process, stream, callback, encoding, bufferSize);
this.messageQueue = new Queue();
}
private void Init(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
{
this.process = process;
this.stream = stream;
this.encoding = encoding;
this.userCallBack = callback;
this.decoder = encoding.GetDecoder();
if (bufferSize < 128)
{
bufferSize = 128;
}
this.byteBuffer = new byte[bufferSize];
this._maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
this.charBuffer = new char[this._maxCharsPerBuffer];
this.cancelOperation = false;
this.eofEvent = new ManualResetEvent(false);
this.sb = null;
this.bLastCarriageReturn = false;
}
public virtual void Close()
{
this.Dispose(true);
}
void IDisposable.Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && this.stream != null)
{
this.stream.Close();
}
if (this.stream != null)
{
this.stream = null;
this.encoding = null;
this.decoder = null;
this.byteBuffer = null;
this.charBuffer = null;
}
if (this.eofEvent != null)
{
this.eofEvent.Close();
this.eofEvent = null;
}
}
internal void BeginReadLine()
{
if (this.cancelOperation)
{
this.cancelOperation = false;
}
if (this.sb == null)
{
this.sb = new StringBuilder(1024);
this.stream.BeginRead(this.byteBuffer, 0, this.byteBuffer.Length, new AsyncCallback(this.ReadBuffer), null);
return;
}
this.FlushMessageQueue();
}
internal void CancelOperation()
{
this.cancelOperation = true;
}
private void ReadBuffer(IAsyncResult ar)
{
int num;
try
{
num = this.stream.EndRead(ar);
}
catch (IOException)
{
num = 0;
}
catch (OperationCanceledException)
{
num = 0;
}
if (num == 0)
{
lock (this.messageQueue)
{
if (this.sb.Length != 0)
{
this.messageQueue.Enqueue(this.sb.ToString());
this.sb.Length = 0;
}
this.messageQueue.Enqueue(null);
}
try
{
this.FlushMessageQueue();
return;
}
finally
{
this.eofEvent.Set();
}
}
int chars = this.decoder.GetChars(this.byteBuffer, 0, num, this.charBuffer, 0);
this.sb.Append(this.charBuffer, 0, chars);
this.GetLinesFromStringBuilder();
this.stream.BeginRead(this.byteBuffer, 0, this.byteBuffer.Length, new AsyncCallback(this.ReadBuffer), null);
}
private void GetLinesFromStringBuilder()
{
int i = 0;
int num = 0;
int length = this.sb.Length;
if (this.bLastCarriageReturn && length > 0 && this.sb[0] == '\n')
{
i = 1;
num = 1;
this.bLastCarriageReturn = false;
}
while (i < length)
{
char c = this.sb[i];
if (c == '\r' || c == '\n')
{
if (c == '\r' && i + 1 < length && this.sb[i + 1] == '\n')
{
i++;
}

string obj = this.sb.ToString(num, i + 1 - num);

num = i + 1;

lock (this.messageQueue)
{
this.messageQueue.Enqueue(obj);
}
}
i++;
}

// Flush Fix: Send Whatever is left in the buffer
string endOfBuffer = this.sb.ToString(num, length - num);
lock (this.messageQueue)
{
this.messageQueue.Enqueue(endOfBuffer);
num = length;
}
// End Flush Fix

if (this.sb[length - 1] == '\r')
{
this.bLastCarriageReturn = true;
}
if (num < length)
{
this.sb.Remove(0, num);
}
else
{
this.sb.Length = 0;
}
this.FlushMessageQueue();
}
private void FlushMessageQueue()
{
while (this.messageQueue.Count > 0)
{
lock (this.messageQueue)
{
if (this.messageQueue.Count > 0)
{
string data = (string)this.messageQueue.Dequeue();
if (!this.cancelOperation)
{
this.userCallBack(data);
}
}
continue;
}
break;
}
}
internal void WaitUtilEOF()
{
if (this.eofEvent != null)
{
this.eofEvent.WaitOne();
this.eofEvent.Close();
this.eofEvent = null;
}
}
}

public class DataReceivedEventArgs : EventArgs
{
internal string _data;
/// <summary>Gets the line of characters that was written to a redirected <see cref="T:System.Diagnostics.Process" /> output stream.</summary>
/// <returns>The line that was written by an associated <see cref="T:System.Diagnostics.Process" /> to its redirected <see cref="P:System.Diagnostics.Process.StandardOutput" /> or <see cref="P:System.Diagnostics.Process.StandardError" /> stream.</returns>
/// <filterpriority>2</filterpriority>
public string Data
{
get
{
return this._data;
}
}
internal DataReceivedEventArgs(string data)
{
this._data = data;
}
}
}

将其粘贴到您的项目中,然后更改...

Process p = new Process()
{
....

FixedProcess p = new FixedProcess()
{
....

现在您的应用程序应该显示如下内容...

Microsoft Windows [Version 6.1.7601]

Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Projects\FixedProcess\bin\Debug>

无需对现有代码进行任何其他更改。它仍然是异步的并且很好地包装了。需要注意的是,现在您将获得大量输出的多个事件,中间可能会有中断,因此您需要自己处理这种情况。除此之外,应该一切都好。

关于C# : Redirect console application output : How to flush the output?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1033648/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com