デコーダーやバイトシフトについて心配することなく、バイトと構造化された値の型を非同期で読み書きしたいのですが、それを可能にするものはありますか?
3 に答える
BinaryReader
またはでは不可能BinaryWriter
です。基になる から同時に読み取ることができますBaseStream
が、ドキュメントには次のように記載されています。
読み取り中または BinaryReader の使用中に基になるストリームを使用すると、データの損失や破損が発生する可能性があります。たとえば、同じバイトが複数回読み取られたり、バイトがスキップされたり、文字の読み取りが予測不能になったりする可能性があります。
したがって、唯一の方法は、独自の実装を展開することです。しかし、それを行う利点については議論の余地があります。Microsoft の Marco Greg が次のコメントをブログ記事に追加しました: 同期メソッドの非同期ラッパーを公開する必要がありますか? :
Jon: BinaryReader/Writer に XxxAsync メソッドがない理由は、これらの型のメソッドは通常、以前に開かれた基になるストリームからごくわずかなバイトしか読み書きしないためです。実際には、データは頻繁にキャッシュされ、基になるソースからデータを取得するのに必要な時間は通常非常に短いため、非同期で行う価値はありません。
特に、これらの型には、状況によっては大量のデータを転送する可能性のあるメソッドがいくつかあります (例: ReadString)。今後は、これらのメソッドの Async バージョンが追加される場合と追加されない場合がありますが、近い将来に発生する可能性は低いです。
一般に、読み取るデータの量が多い場合 (少なくとも数百または数千バイト)、またはリソースに初めてアクセスする場合 (ファイルからの最初の読み取りなど) にのみ、非同期 IO メソッドを検討する必要があります。 1 バイトを読み取る場合でも、ディスクをスピンアップする必要がある場合があります)。
これは合理的に聞こえます。解決策が必要な場合は、独自のBinaryReader
/をローリングする以外にいくつかの回避策がありますBinaryWriter
。別のスレッドで実行することができます (非効率的です)。または、ファイル形式やワイヤ プロトコルを変更する場合は、次のパターン (疑似コード) を使用できます。
//read packet length
await stream.ReadAsync(buffer);
var packetLength=convertToInt(buffer);
//read complete packet asynchronously
await stream.ReadAsync(buffer,packetLength);
//process packet with BinaryReader
using(var br=new BinaryReader(new MemoryStream(buffer))
{
//...
}
このパターンは、バッファ全体が簡単にメモリに収まる場合にのみ有用であり、パフォーマンスが低下する可能性があることに注意してください。
これらのクラスの非同期バージョンを作成しました: https://github.com/ronnieoverby/AsyncBinaryReaderWriter
使用例:
async Task Main()
{
using var ms = new MemoryStream();
using var writer = new AsyncBinaryWriter(ms);
await writer.WriteAsync("today is: ");
await writer.WriteAsync(DateTime.Today.Ticks);
await writer.FlushAsync();
ms.Position = 0;
using var reader = new AsyncBinaryReader(ms);
var preamble = await reader.ReadStringAsync();
var payload = new DateTime(await reader.ReadInt64Async());
Console.WriteLine(preamble + payload);
}
BCL バイナリ リーダー/ライター クラスに存在する同じ読み取り/書き込みメソッドがすべて存在します。