StreamWriter和UTF-8字节顺序标记

我遇到了StreamWriter和Byte Order Marks的问题。 该文件似乎说明Encoding.UTF8编码已启用字节顺序标记,但是当文件正在写入一些有标记而其他没有。

我正在用以下方式创buildstream式编写器:

this.Writer = new StreamWriter( this.Stream , System.Text.Encoding.UTF8 ); 

任何可能发生的想法,将不胜感激。

正如有人指出的那样,没有编码参数的调用就可以实现。 但是,如果你想明确,试试这个:

 using (var sw = new StreamWriter("text.txt", new UTF8Encoding(false))) 

关键是构造一个新的UTF8Encoding(false),而不是使用Encoding.UTF8Encoding。 这是为了控制是否应该添加BOM。

这与调用没有编码参数的StreamWriter相同,在内部它只是做同样的事情。

唯一一次,我看到构造函数不添加UTF-8 BOM,如果stream调用它时不在位置0。 例如,在下面的代码中,BOM不写入:

 using (var s = File.Create("test2.txt")) { s.WriteByte(32); using (var sw = new StreamWriter(s, Encoding.UTF8)) { sw.WriteLine("hello, world"); } } 

正如其他人所说,如果您使用StreamWriter(stream)构造函数,而不指定编码,那么您将看不到BOM。

这个问题是由于您在Encoding类中使用了静态UTF8属性 。

当在UTF8属性返回的Encoding类的实例上调用GetPreamble方法时 ,它将返回字节顺序标记(三个字符的字节数组),并在将任何其他内容写入stream之前写入stream一个新的stream)。

您可以通过自己创buildUTF8Encoding类的实例来避免这种情况,如下所示:

 // As before. this.Writer = new StreamWriter(this.Stream, // Create yourself, passing false will prevent the BOM from being written. new System.Text.UTF8Encoding()); 

根据默认的无参数构造函数的文档(重点是我的):

此构造函数创build一个实例,该实例不会提供Unicode字节顺序标记 ,并且在检测到无效编码时不会引发exception。

这意味着对GetPreamble的调用将返回一个空数组,因此不会将BOM写入底层stream。

我的答案是基于HelloSam的一个包含所有必要的信息。 只有我相信OP所要求的是如何确保BOM被排放到文件中。

所以,而不是传递false到UTF8Encoding ctor你需要传递true。

  using (var sw = new StreamWriter("text.txt", new UTF8Encoding(true))) 

试试下面的代码,在hex编辑器中打开生成的文件,看看哪一个包含BOM,哪个不包含。

 class Program { static void Main(string[] args) { const string nobomtxt = "nobom.txt"; File.Delete(nobomtxt); using (Stream stream = File.OpenWrite(nobomtxt)) using (var writer = new StreamWriter(stream, new UTF8Encoding(false))) { writer.WriteLine("HelloПривет"); } const string bomtxt = "bom.txt"; File.Delete(bomtxt); using (Stream stream = File.OpenWrite(bomtxt)) using (var writer = new StreamWriter(stream, new UTF8Encoding(true))) { writer.WriteLine("HelloПривет"); } } 

你使用每个文件的StreamWriter相同的构造函数吗? 因为文档说:

要使用UTF-8编码和BOM创buildStreamWriter,请考虑使用指定编码的构造函数,如StreamWriter(String,Boolean,Encoding)。

我前一段时间也处于类似的状况。 我最终使用Stream.Write方法而不是StreamWriter,并在编写Encoding.GetBytes(stringToWrite)之前写入Encoding.GetPreamble()的结果,

似乎如果文件已经存在并且不包含BOM,那么在覆盖时它将不包含BOM,换句话说,StreamWriter在覆盖文件时保留BOM(或不存在)。

我发现这个答案很有用(感谢@Philipp Grathwohl和@Nik),但在我的情况下,我使用FileStream来完成任务,所以生成物料清单的代码如下所示:

 using (FileStream vStream = File.Create(pfilePath)) { // Creates the UTF-8 encoding with parameter "encoderShouldEmitUTF8Identifier" set to true Encoding vUTF8Encoding = new UTF8Encoding(true); // Gets the preamble in order to attach the BOM var vPreambleByte = vUTF8Encoding.GetPreamble(); // Writes the preamble first vStream.Write(vPreambleByte, 0, vPreambleByte.Length); // Gets the bytes from text byte[] vByteData = vUTF8Encoding.GetBytes(pTextToSaveToFile); vStream.Write(vByteData, 0, vByteData.Length); vStream.Close(); } 

你能不能展示一下它不生产的情况? 唯一没有出现序言的情况是我没有写过任何东西(吉姆·米歇尔似乎find了另外一个逻辑的,更可能是你的问题,看到了答案)。

我的testing代码:

 var stream = new MemoryStream(); using(var writer = new StreamWriter(stream, System.Text.Encoding.UTF8)) { writer.Write('a'); } Console.WriteLine(stream.ToArray() .Select(b => b.ToString("X2")) .Aggregate((i, a) => i + " " + a) ); 
Interesting Posts