[C#] Stream 支援寫入讀取觸發事件的類庫 繼承Stream基類
阿新 • • 發佈:2021-02-04
[C#] Stream 支援寫入讀取觸發事件的類庫
實現了 :
- 你可以將這個流類的例項提供給某些東西, 在它操作這個流時, 你可以通過事件來接收到訊息, 並加以處理, 例如拒絕寫入, 或在寫入前判斷寫入的內容. 你可以稍微改動一下這個類以適應你的需求.
- 應用場景: 例如你使用了 IronPython 庫, 並使用它執行了一些操作, 你希望 IronPython 每次 print 時, 你都能獲取到內容, 則, 你可以使用這個觸發流(TriggerStream)類, 將 IronPython 引擎的標準輸出流設定為觸發流的例項, 這樣, 每當 IronPython 有內容輸出時, 你都能獲取到內容. 例如這個專案:
- 應用場景: 例如, 你運行了一個 Process, 並且希望實時獲取它的輸出內容, 而不是執行完之後一次性獲取所有內容, 同理, 你可以設定它的標準輸出流為觸發流例項, 然後每次它輸出內容你都能接收到.
原始碼 :
1. 首先是僅僅包含觸發器, 而不會有任何儲存行為的類
using System;
using System.IO;
namespace Null.Library.TriggerStream
{
class WriteStreamEventArgs : EventArgs
{
public byte[] Buffer;
public int Offset, Count;
public bool Denied = false;
}
class TriggerStream : Stream
{
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => 0;
public override long Position { get => 0; set { } }
public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
return 0;
}
public override long Seek(long offset, SeekOrigin origin)
{
return 0;
}
public override void SetLength(long value) { }
public override void Write(byte[] buffer, int offset, int count)
{
if (PreviewWrite != null)
PreviewWrite.Invoke(this, new WriteStreamEventArgs()
{
Buffer = buffer,
Offset = offset,
Count = count,
});
}
public event EventHandler<WriteStreamEventArgs> PreviewWrite;
}
}
很明顯能夠看出, 上面的這個, 僅有事件觸發, 而Seek, Read, Position等方法及屬性, 都是直接使用的空或者返回合適的固定值.
2. 然後是帶有儲存功能的(使用MemoryStream)類
using System;
using System.IO;
namespace Null.Library.EventedStream
{
class ReadStreamEventArgs : EventArgs
{
public byte[] Buffer;
public int Offset, Count;
public bool Denied = false;
}
class WriteStreamEventArgs : EventArgs
{
public byte[] Buffer;
public int Offset, Count;
public bool Denied = false;
}
public class FlushStreamEventArgs : EventArgs
{
public bool Denied = false;
}
public class SetStreamLengthEventArgs : EventArgs
{
public long Value;
public bool Denied = false;
}
public class SeekStreamEventArgs : EventArgs
{
public long Offset;
public SeekOrigin SeekOrigin;
public bool Denied = false;
}
class EventedStream : Stream, IDisposable
{
MemoryStream baseMemory = new MemoryStream();
public override bool CanRead => baseMemory.CanRead;
public override bool CanSeek => baseMemory.CanSeek;
public override bool CanWrite => baseMemory.CanWrite;
public override long Length => baseMemory.Length;
public override long Position { get => baseMemory.Position; set => baseMemory.Position = value; }
public override void Flush()
{
if (PreviewFlush != null)
{
FlushStreamEventArgs args = new FlushStreamEventArgs();
PreviewFlush.Invoke(this, args);
if (args.Denied)
return;
}
baseMemory.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
if (PreviewRead != null)
{
ReadStreamEventArgs args = new ReadStreamEventArgs()
{
Buffer = buffer,
Offset = offset,
Count = count
};
PreviewRead.Invoke(this, args);
if (args.Denied)
return 0;
}
return baseMemory.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
if (PreviewSeek != null)
{
SeekStreamEventArgs args = new SeekStreamEventArgs()
{
Offset = offset,
SeekOrigin = origin
};
PreviewSeek.Invoke(this, args);
if (args.Denied)
return Position;
}
return baseMemory.Seek(offset, origin);
}
public override void SetLength(long value)
{
if (PreviewSetLength != null)
{
SetStreamLengthEventArgs args = new SetStreamLengthEventArgs()
{
Value = value
};
PreviewSetLength.Invoke(this, args);
if (args.Denied)
return;
}
baseMemory.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (PreviewWrite != null)
{
WriteStreamEventArgs args = new WriteStreamEventArgs()
{
Buffer = buffer,
Offset = offset,
Count = count
};
PreviewWrite.Invoke(this, args);
if (args.Denied)
return;
}
baseMemory.Write(buffer, offset, count);
}
public new void Dispose()
{
baseMemory.Dispose();
}
public event EventHandler<FlushStreamEventArgs> PreviewFlush;
public event EventHandler<SetStreamLengthEventArgs> PreviewSetLength;
public event EventHandler<SeekStreamEventArgs> PreviewSeek;
public event EventHandler<WriteStreamEventArgs> PreviewWrite;
public event EventHandler<ReadStreamEventArgs> PreviewRead;
}
}
原理 :
倒也簡單, 直接繼承基類, 然後實現方法即可.
提示 :
如果你要同時使用這兩個, 別忘記稍微移動下事件引數使它們在同一個檔案中, 並使兩個事件流類using事件引數的名稱空間, 否則, 在不完全指定名稱空間的狀況下, 會出現不明確引用的錯誤.