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