C# StreamWriter和UTF-8字节顺序标记

C# StreamWriter和UTF-8字节顺序标记,c#,file-encodings,C#,File Encodings,我对StreamWriter和字节顺序标记有问题。文档似乎说明Encoding.UTF8编码已启用字节顺序标记,但在写入文件时,有些文件具有标记,而另一些文件没有 我以以下方式创建流编写器: this.Writer = new StreamWriter(this.Stream, System.Text.Encoding.UTF8); 任何关于可能发生的事情的想法都将不胜感激 是否对每个文件使用相同的StreamWriter构造函数?因为文件上说: < >使用UTF-8编码和BOM创建流写器,考

我对StreamWriter和字节顺序标记有问题。文档似乎说明Encoding.UTF8编码已启用字节顺序标记,但在写入文件时,有些文件具有标记,而另一些文件没有

我以以下方式创建流编写器:

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

任何关于可能发生的事情的想法都将不胜感激

是否对每个文件使用相同的StreamWriter构造函数?因为文件上说:

< >使用UTF-8编码和BOM创建流写器,考虑使用指定编码的构造函数,如StreamWriter(String,BooLoin,编码)。


不久前我也遇到过类似的情况。我最终使用了该方法而不是StreamWriter,并在编写
编码.GetBytes(stringToWrite)
之前编写了
编码.getPremission()的结果?因为文件上说:

< >使用UTF-8编码和BOM创建流写器,考虑使用指定编码的构造函数,如StreamWriter(String,BooLoin,编码)。


不久前我也遇到过类似的情况。在编写
Encoding.GetBytes(stringToWrite)
之前,我使用了该方法而不是StreamWriter,并编写了
Encoding.getPremission()的结果。例如,在下面的代码中,没有写入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。

我唯一一次看到构造函数没有添加UTF-8 BOM的情况是,当您调用它时,如果流不在位置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。

您能否显示一种它不生成BOM的情况?我能找到的唯一一个序言没有出现的情况是,没有人给作者写任何东西(吉姆·米切尔似乎已经找到了另一个更符合逻辑、更可能是你的问题的答案)

我的测试代码:

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

你能不能展示一个它不能产生它的情况?我能找到的唯一一个序言没有出现的情况是,没有人给作者写任何东西(吉姆·米切尔似乎已经找到了另一个更符合逻辑、更可能是你的问题的答案)

我的测试代码:

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

如果文件已存在且不包含BOM,则覆盖时将不包含BOM,换句话说,StreamWriter在覆盖文件时保留BOM(或不包含BOM)。

如果文件已存在且不包含BOM,则覆盖时将不包含BOM,换句话说,StreamWriter在覆盖文件时保留BOM(或其不存在)。

正如有人已经指出的那样,在不使用编码参数的情况下调用会起到作用。 但是,如果要明确,请尝试以下方法:

using (var sw = new StreamWriter(this.Stream, new UTF8Encoding(false)))
要禁用BOM,关键是使用
新的UTF8Encoding(false)
构建,而不仅仅是Encoding.UTF8Encoding。这与在没有编码参数的情况下调用StreamWriter是一样的,在内部它只是做同样的事情

要启用BOM,请改用新的UTF8Encoding(true)


更新:从Windows 10 v1903开始,当在notepad.exe中另存为UTF-8时,BOM字节现在是一个可选的功能。

正如有人指出的那样,不带编码参数调用就可以了。 但是,如果要明确,请尝试以下方法:

using (var sw = new StreamWriter(this.Stream, new UTF8Encoding(false)))
要禁用BOM,关键是使用
新的UTF8Encoding(false)
构建,而不仅仅是Encoding.UTF8Encoding。这与在没有编码参数的情况下调用StreamWriter是一样的,在内部它只是做同样的事情

要启用BOM,请改用新的UTF8Encoding(true)


更新:从Windows 10 v1903开始,当在notepad.exe中另存为UTF-8时,BOM字节现在是一个选择加入功能。

问题是由于您在上使用了静态

UTF8
属性返回的
Encoding
类的实例上调用时,它返回字节顺序标记(三个字符的字节数组),并在将任何其他内容写入流(假定为新流)之前写入流

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

// As before.
this.Writer = new StreamWriter(this.Stream, 
    // Create yourself, passing false will prevent the BOM from being written.
    new System.Text.UTF8Encoding());
根据(重点矿山)的文件:

此构造函数创建的实例不提供Unicode字节顺序标记,并且在检测到无效编码时不会引发异常


这意味着对
GetPreamble
的调用将返回一个空数组,因此不会将任何BOM写入基础流。

问题是由于您在上使用了static

UTF8
属性返回的
Encoding
类的实例上调用时,它返回字节顺序标记(三个字符的字节数组),并在将任何其他内容写入流(假定为新流)之前写入流

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

// As before.
this.Writer = new StreamWriter(this.Stream, 
    // Create yourself, passing false will prevent the BOM from being written.
    new System.Text.UTF8Encoding());
根据(重点矿山)的文件:

此构造函数创建的实例不提供Unicode字节顺序标记,并且在检测到无效编码时不会引发异常


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

我的答案基于HelloSam的一个,其中包含所有必要的inf