![](/img/trans.png)
[英]Is there a C# equivalent way for Java InputStream and OutputStream?
[英]How do you pass an OutputStream as an InputStream in C#?
我的目標是從一個流中讀取,轉換該流,並將其用作接受要讀取的Stream
的庫的輸入。
我正在使用兩個不同的庫。 一個獲取輸出Stream
並將其轉換。 我們稱其為TransformingOutputStream
。 其預期用途是:
var outputStream = new TransformingOutputStream(finalDestinationOutputStream);
inputStream.CopyTo(outputStream);
我正在使用另一個接受輸入Stream
庫。 它執行所需的任何操作,然后從該流中讀取。 其預期用途是:
MagicStreamReadingLibrary.ProcessStream(someInputStream);
我不能將TransformingOutputStream
傳遞給它,因為它的預期用途是寫入而不是讀取。 我無法控制任何一個庫。
如何將TransformingOutputStream
到需要從輸入Stream
讀取的庫函數?
到目前為止,這是我使用匿名管道的最佳工作示例:
using( var pipeServer = new AnonymousPipeServerStream( PipeDirection.Out ) ) {
var pipeServerTask = Task.Run(
async () => {
using( var stream = getInputStream() ) {
await stream.CopyToAsync( new TransformingOutputStream( pipeServer ) );
}
pipeServer.WaitForPipeDrain();
pipeServer.Dispose();
} );
using( var client = new AnonymousPipeClientStream( PipeDirection.In, pipeServer.ClientSafePipeHandle ) ) {
MagicStreamReadingLibrary.ProcessStream( client );
}
pipeServerTask.Wait();
}
將其寫入平面文件,然后將其讀出。
這是我剛剛匯總的內容,理論上應該可以工作(未經測試,我只知道它可以正確編譯)。
public class BufferingStream
{
private readonly Stream _readingStream;
private readonly Stream _writingStream;
private BlockingCollection<byte[]> _buffer;
public BufferingStream()
{
_buffer = new BlockingCollection<byte[]>(new ConcurrentQueue<byte[]>());
_readingStream = new InternalReadingStream(_buffer);
_writingStream = new InternalWritingStream(_buffer);
}
public BufferingStream(int maxQueueLength)
{
_buffer = new BlockingCollection<byte[]>(new ConcurrentQueue<byte[]>(), maxQueueLength);
_readingStream = new InternalReadingStream(_buffer);
_writingStream = new InternalWritingStream(_buffer);
}
public Stream GetReadingStream()
{
return _readingStream;
}
public Stream GetWritingStream()
{
return _writingStream;
}
public int QueueLength
{
get { return _buffer.Count; }
}
public class InternalWritingStream : Stream
{
private readonly BlockingCollection<byte[]> _queuedBytes;
public InternalWritingStream(BlockingCollection<byte[]> queuedBytes)
{
_queuedBytes = queuedBytes;
}
public override void Write(byte[] buffer, int offset, int count)
{
byte[] internalBuffer = new byte[count];
Array.Copy(buffer, offset, internalBuffer, 0, count);
_queuedBytes.Add(internalBuffer);
}
public override void Close()
{
_queuedBytes.CompleteAdding();
base.Close();
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return false; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
private sealed class InternalReadingStream : Stream
{
private readonly BlockingCollection<byte[]> _queuedBytes;
private byte[] _currentItem;
private int _currentItemOffset;
public InternalReadingStream(BlockingCollection<byte[]> queuedBytes)
{
_queuedBytes = queuedBytes;
_currentItem = new byte[0];
_currentItemOffset = 0;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_currentItemOffset == _currentItem.Length)
{
//Try to take the next buffer, if we can't take a item it means we where done adding from the source.
var taken = _queuedBytes.TryTake(out _currentItem, Timeout.Infinite);
if (!taken)
return 0;
_currentItemOffset = 0;
}
var bytesToRead = Math.Min(count, _currentItem.Length - _currentItemOffset);
Array.Copy(_currentItem, _currentItemOffset, buffer, offset, bytesToRead);
_currentItemOffset += bytesToRead;
return bytesToRead;
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
}
它在您的用例中的工作方式將是
var bufferingStream = new BufferingStream();
Task.Run(() =>
{
using(var inputStream = GetTheStreamFromSomewhere();
using(var finalDestinationOutputStream = bufferingStream.GetWritingStream())
using(var outputStream = new TransformingOutputStream(finalDestinationOutputStream))
{
inputStream.CopyTo(outputStream);
}
}
using(var someInputStream = bufferingStream.GetReadingStream()) //Technically a using is not necessary on the reading stream but it is good to keep good habits.
{
MagicStreamReadingLibrary.ProcessStream(someInputStream);
}
最初對.Read(
調用將由ProcessStream
進行調用,直到數據變得可用為止。當字節變為可用時.Read(
解除阻止並傳遞數據。一旦處理了finalDestinationOutputStream
,它將標記為完成添加隊列,並且一旦outputStream
完成了對它的最后一次讀取后續的任何調用只會返回0。
如果發現作家比讀者快得多,則可能需要傳遞最大隊列長度,這樣寫操作將阻塞,直到讀者有機會閱讀為止。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.