【问题标题】:StreamWriter is appending BOM character 65279 to end of fileStreamWriter 将 BOM 字符 65279 附加到文件末尾
【发布时间】:2015-02-02 15:13:16
【问题描述】:

我在读取文件的同时打开了一个StreamWriter 文件,这似乎导致了问题(这是一组较大代码中的一个较小的 sn-p,只是为了说明我的问题):

static void Main(string[] args)
{
    for (int i = 0; i < 3; i++)
    {
        using (FileStream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true))
        using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 0x1000, true))
        {
            Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file.");
        }
    }
    Console.ReadLine();
}

上面的代码会输出:

Read "" from the file.
Read "" from the file.
Read "?" from the file.

如果文件已经包含一些文本,编写器会将 BOM 附加到末尾,尽管从未被调用写入任何内容:

Read "TEXT" from the file.
Read "TEXT?" from the file.
Read "TEXT??" from the file.

为什么会出现这种行为?

【问题讨论】:

  • @grovesNL 这是关于 StreamReader,而不是关于 GetString,这些答案对我没有帮助。
  • @grovesNL 即使它是 BOM 值,我会惊讶地看到它在结尾而不是开头...
  • @Alexandru 如果 BOM (0xFEFF) 一开始就与 StreamReader 有关。因为这...可能您的文件刚刚损坏。
  • 在同一个流上拥有一个阅读器和一个作者通常不是一个好主意...

标签: c# .net io stream streamreader


【解决方案1】:

正如我之前在关于字节顺序标记的评论中暗示的那样,您试图避免使用StreamWriter 添加字节顺序标记。这取决于您使用的编码器。

例如,尝试创建自己的编码器而不编写字节顺序标记:

static void Main(string[] args)
{
    for (int i = 0; i < 3; i++)
    {
        using (FileStream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, true, 0x1000, true))
        using (StreamWriter writer = new StreamWriter(stream, new UTF8Encoding(false), 0x1000, true))
        {
            Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file.");
        }
    }
    Console.ReadLine();
}

通过使用 new UTF8Encoding(false) 作为 UTF8 编码器,明确指示编码器不要使用 Unicode 字节顺序标记。这在MSDN entry for the UTF8Encoding constructor 中有描述。

【讨论】:

  • 是的,这行得通。我想我正在使用 StreamReader 读取到流的末尾......然后编写器将被处理,并且在处理时我认为流编写器认为它位于流的开头,因为它没有被调用,追加UTF8 的 BOM 标志,这并不聪明,因为它应该读取 FileStream 的位置以了解它的位置。如果没有这些标志,您必须立即知道编码才能打开并从文件中读取。我说的对吗?
  • @Alexandru:是的,当您在拨打Console.WriteLine 之前写信给您的writer 时会更清楚地表达出来。只需尝试添加writer.Write("test") 并观察字节顺序标记是如何附加的。
【解决方案2】:

嗯。我认为即使您不写任何东西,作者也想写字节顺序标记。您将流位置移动到流的末尾,因此当您处理写入器时 - 它会将字节顺序标记刷新到流的末尾。

试试这个代码

    static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            using (FileStream stream = new FileStream("sample.txt", FileMode.OpenOrCreate))
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true))
            using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 0x1000, true))
            {
                writer.Flush();
                Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file.");
            }
        }
        Console.ReadLine();
    }

您将看到预期的行为,没有“?”符号。

【讨论】:

  • 我希望我能接受两个答案,但格罗夫斯确实打败了你。人:如果你读到这个,这也是一个非常可靠的方法。 Taukita,这将导致编写器始终确保它 BOM 标记文件的开头。
  • 这真的很棒。我在我正在编写的库中采用了这种方法,因为这为您提供了新文件开头的正确 BOM 标记。
猜你喜欢
  • 2017-06-15
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 2014-03-06
  • 2020-08-19
  • 2017-09-29
  • 1970-01-01
相关资源
最近更新 更多