2014-12-04 127 views
0

我有一个StreamWriter在我读取它的同时打开我的文件,这似乎是导致问题的原因(这是更大的一组代码中的一个较小片段,只是以说明我的问题):StreamWriter正在将BOM字符65279附加到文件结尾

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. 

它为什么会表现出这种行为?

+0

可能的重复[如何忽略字符串比较中的UTF-8字节顺序标记?](http://stackoverflow.com/questions/2915182/how-do-i-ignore-the-utf-8-字节顺序标记在字符串比较) – grovesNL 2014-12-04 16:35:39

+0

@grovesNL这是关于StreamReader,而不是关于GetString,这些答案不帮助我。 – Alexandru 2014-12-04 16:41:51

+1

@grovesNL即使它的BOM值我会很惊讶地看到**在最后**而不是开始... – 2014-12-04 16:41:59

回答

3

正如我以前在关于字节顺序标记的评论中暗示的,您试图避免在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中描述。

+0

是的,这是有效的。我想我正在使用StreamReader读取数据流的末尾...然后作者将被丢弃,并且在处置时,我想流处理器认为它在流的起始处,因为它没有被调用,所以追加BOM标志为UTF8,这是不智能的,因为它应该读取FileStream的位置以知道它在哪里。如果没有这些标志,您只需要知道编码就可以从文件中打开并读取。我对吗? – Alexandru 2014-12-04 17:35:09

+1

@亚历山大:是的,在你的'Console.WriteLine'调用之前写入你的'writer'时,它会更清楚地表达出来。只要尝试添加'writer.Write(“test”)'并观察如何添加字节顺序标记。 – grovesNL 2014-12-04 17:42:50

1

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

试试这个代码

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(); 
    } 

你会看到预期的行为,不 '?'符号。

+0

我希望我能接受两个答案,但树丛击败了你。人们:如果你阅读这个,这也是一个非常可靠的方法。 Taukita,这会导致作者始终确保它在开始时标记文件。 – Alexandru 2014-12-04 17:46:39

+0

这工作真的很棒。我在我正在写的库中采用了这种方法,因为这给了你一个新文件开始时的正确的BOM标签。 – Alexandru 2014-12-04 19:00:23