【问题标题】:Difference in writing string vs. char array with System.IO.BinaryWriter使用 System.IO.BinaryWriter 写入字符串与 char 数组的区别
【发布时间】:2009-06-18 19:30:50
【问题描述】:

我正在用 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 个字节。谁能解释一下?

【问题讨论】:

  • btw - 如果您只是想序列化您的数据,可以使用 API 来帮助解决这个问题 - 任何内置的序列化器,或者有一系列可用的 3rd 方序列化器。通常比编写大量自己的读/写代码更强大...

标签: c# string encoding file binaryfiles


【解决方案1】:

BinaryWriter.Write(string) 的文档声明它会将一个以长度为前缀的字符串写入此流。 Write(char[]) 的重载没有这样的前缀。

在我看来,额外的数据就是长度。

编辑:

为了更明确一点,使用反射器。你会看到它有这段代码作为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;当您查看如何读取数据时,差异会变得更加明显;使用 BinaryReader.ReadChars 你需要告诉它要读多少;使用 BinaryReader.ReadString 它使用长度前缀为您执行此操作。
  • @Marc:很好。这两个绝对是为了相互补充而编写的,并且 Write(string) 方法在“但是现在我如何读取该数据?”的上下文中更有意义
【解决方案2】:

来自BinaryWriter.Write(string)docs

以BinaryWriter的当前编码向该流写入一个length-prefixed字符串,并根据使用的编码和写入流的具体字符将流的当前位置提前.

这种行为可能是因为当使用BinaryReader 读回文件时,可以识别字符串。 (例如,3Foo3Bar6Foobar 可以解析为字符串“Foo”、“Bar”和“Foobar”,但 FooBarFoobar 不能。)事实上,BinaryReader.ReadString 正是使用此信息从二进制文件中读取 string文件。

来自BinaryWriter.Write(char[])docs

将字符数组写入当前流,并根据使用的编码和写入流的特定字符推进流的当前位置。

很难夸大 MSDN 上的文档的全面性和实用性。始终先检查它们。

【讨论】:

    【解决方案3】:

    如前所述,BinaryWriter.Write(String) 在写入字符串本身之前将字符串的长度写入流。

    这允许 BinaryReader.ReadString() 知道字符串的长度。

    using (BinaryReader br = new BinaryReader(File.OpenRead("data.dat")))
    {
        string foo1 = br.ReadString();
        char[] foo2 = br.ReadChars(3);
    }
    

    【讨论】:

      【解决方案4】:

      你看过实际写的内容吗?我猜是一个空终止符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-09
        • 2011-10-02
        • 2012-05-18
        相关资源
        最近更新 更多