我正在使用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());
}
我不明白为什么当我只写3个ASCII字符时,字符串重载会写入4个字节。谁能解释一下呢?
答案 0 :(得分:13)
BinaryWriter.Write(string)
的文档声明它将长度为前缀的字符串写入此流。 Write(char[])
的重载没有这样的前缀。
在我看来,额外的数据就是长度。
编辑:
为了更明确一点,请使用Reflector。您将看到它在Write(string)
方法中包含这段代码:
this.Write7BitEncodedInt(byteCount);
这是一种使用尽可能少的字节数对整数进行编码的方法。对于短字符串(我们将每天使用少于128个字符),它可以使用一个字节表示。对于更长的字符串,它开始使用更多字节。
以下是您感兴趣的函数代码:
protected void Write7BitEncodedInt(int value)
{
uint num = (uint) value;
while (num >= 0x80)
{
this.Write((byte) (num | 0x80));
num = num >> 7;
}
this.Write((byte) num);
}
使用此编码为长度添加前缀后,它会以所需的编码写入字符的字节。
答案 1 :(得分:5)
来自BinaryWriter.Write(string)
docs:
在BinaryWriter的当前编码中将长度前缀字符串写入此流,并根据使用的编码和写入流的特定字符推进流的当前位置
这种行为可能是因为当使用BinaryReader
重新读取文件时,可以识别字符串。 (例如3Foo3Bar6Foobar
可以解析为字符串“Foo”,“Bar”和“Foobar”但FooBarFoobar
不能解析。)实际上,BinaryReader.ReadString
正好使用此信息来读取来自二进制文件的string
。
来自BinaryWriter.Write(char[])
docs:
将字符数组写入当前流,并根据使用的编码和写入流的特定字符推进流的当前位置。
很难夸大MSDN上文档的全面性和实用性。务必先检查它们。
答案 2 :(得分:1)
如前所述,BinaryWriter.Write(String)在写入字符串之前将字符串的长度写入流中。
这允许BinaryReader.ReadString()知道字符串的长度。
using (BinaryReader br = new BinaryReader(File.OpenRead("data.dat")))
{
string foo1 = br.ReadString();
char[] foo2 = br.ReadChars(3);
}
答案 3 :(得分:0)
你看过实际写的是什么吗?我猜一个空终结器。