System.IO.BinaryWriterを使用した文字列とchar配列の書き込みの違い
-
06-07-2019 - |
質問
私はC#でバイナリファイルにテキストを書き込んでおり、文字列と文字配列の書き込みで書き込まれた量の違いを確認しています。 System.IO.BinaryWriterを使用し、書き込みが発生するにつれてBinaryWriter.BaseStream.Lengthを監視しています。これらは私の結果です:
using(BinaryWriter bw = new BinaryWriter(File.Open(“data.dat”), Encoding.ASCII))
{
string value = “Foo”;
// Writes 4 bytes
bw.Write(value);
// Writes 3 bytes
bw.Write(value.ToCharArray());
}
ASCII文字を3つしか書き込んでいないのに、なぜ文字列のオーバーロードが4バイトを書き込むのか理解できません。誰でもこれを説明できますか?
解決
BinaryWriter.Write(string)
のドキュメントは、このストリームに長さの接頭辞付き文字列を書き込むことを示しています。 Write(char [])
このような接頭辞はありません。
余分なデータは長さのように思えます。
編集:
もう少し明確にするために、Reflectorを使用します。 Write(string)
メソッドの一部として、次のコードが含まれていることがわかります。
this.Write7BitEncodedInt(byteCount);
これは、最小限のバイト数を使用して整数をエンコードする方法です。短い文字列(128文字未満の日々を使用する場合)の場合、1バイトを使用して表すことができます。長い文字列の場合、より多くのバイトを使用し始めます。
興味がある場合に備えて、この関数のコードを次に示します。
protected void Write7BitEncodedInt(int value)
{
uint num = (uint) value;
while (num >= 0x80)
{
this.Write((byte) (num | 0x80));
num = num >> 7;
}
this.Write((byte) num);
}
このエンコーディングを使用して長さにプレフィックスを付けた後、目的のエンコーディングで文字のバイトを書き込みます。
他のヒント
BinaryWriter.Write(string)
からドキュメント:
BinaryWriterの現在のエンコーディングでこのストリームに length-prefixed 文字列を書き込み、使用されているエンコーディングとストリームに書き込まれている特定の文字に従ってストリームの現在の位置を進めます。
この動作はおそらく、 BinaryReader
を使用してファイルを読み戻すときに文字列を識別できるようにするためです。 (たとえば、 3Foo3Bar6Foobar
は、文字列" Foo"、" Bar"、" Foobar"に解析できますが、 FooBarFoobar
は解析できません。)実際、 BinaryReader.ReadString
は、この情報を正確に使用して、バイナリファイルから string
を読み取ります。
BinaryWriter.Write(char [])
からドキュメント:
現在のストリームに文字配列を書き込み、使用されているエンコーディングとストリームに書き込まれている特定の文字に従って、ストリームの現在の位置を進めます。
MSDNのドキュメントがどれほど包括的で有用であるかを誇張するのは困難です。必ず最初に確認してください。
すでに述べたように、BinaryWriter.Write(String)は、文字列自体を書き込む前に、文字列の長さをストリームに書き込みます。
これにより、BinaryReader.ReadString()は文字列の長さを知ることができます。
using (BinaryReader br = new BinaryReader(File.OpenRead("data.dat")))
{
string foo1 = br.ReadString();
char[] foo2 = br.ReadChars(3);
}
実際に書かれたものを見ましたか? nullターミネーターを推測します。