使用StringBuilder向字符串添加字节顺序标记

5
如何在 StringBuilder 中添加字节顺序标记? (我必须将字符串传递给另一个方法,该方法将其保存为文件,但我无法修改该方法。)
我尝试了这个:
var sb = new StringBuilder();
sb.Append('\xEF');
sb.Append('\xBB');
sb.Append('\xBF');

但是当我用十六进制编辑器查看时,它会添加以下序列:C3 AF C2 BB C2 BF

字符串很大,因此最好不要来回转换为字节数组。

编辑: 在评论中提出问题后进行澄清。我必须将该字符串传递给另一个方法,该方法接受一个字符串并在Azure Blob Storage上创建一个文件。我无法修改其他方法。


为什么?只有在写入文件时才需要字节顺序标志...您看到的问题是因为字节顺序标记不是Unicode - Peter Ritchie
我必须将字符串传递给另一个方法,该方法接受一个字符串并在Azure Blob Storage上创建一个文件。 - Adam Szabo
4个回答

15

两个选择:

  1. 在您的文本中根本不包括字节顺序标记...而是使用会自动包含它的编码
  2. 将其作为一个字符包含在您的 StringBuilder 中:

  3. sb.Append('\uFEFF'); // U+FEFF is the byte-order mark character
    

个人而言,通常我会选择第一种方法,但“我无法修改该方法”表明在您的情况下可能不是一个选项。


1
谢谢。是的,你说得对,我通常会选择第一个选项,但我采用这种方法是因为我必须将字符串传递给另一个方法,该方法将其作为文件创建在 Azure Blob 存储中。 - Adam Szabo

8

字节顺序标记用于告知读取文件的读者该文件采用特定编码。因此,您只需要在实际文件中使用字节顺序标记(BOM)。如果您想在正在编写的文本文件中包含BOM,请使用StreamWriter将其写入文件。例如:

using(var writer = new StreamWriter(stream, System.Text.Encoding.UTF8))
{
    writer.Write(sb.ToString);
}

如果您不想在UTF-8中使用BOM:

using(var writer = new StreamWriter(stream))
{
    writer.Write(sb.ToString());
}

或者如果您想要不同的BOM:

using(var writer = new StreamWriter(stream, System.Text.Encoding.UTF16))
{
    writer.Write(sb.ToString);
}

更新:

如果您想从BOM的实现细节或特定编码的BOM(即可能在运行时或部署后更改)中分离,但仍想传递带有BOM标记的字符串,则可以像这样操作(假设.NET 4.5):

var stream = new MemoryStream();
var encoding = Encoding.UTF8; // TODO: configurize this, if necessary
using(var writer = new StreamWriter(stream, encoding, 1024, true))
{
    writer.Write(sb.ToString());
}
CantModifyButMustUseThis(encoding.GetString(stream.ToArray());

1
我知道BOM的作用。但是,正如我在问题中提到的那样,我必须将它传递给另一个方法(该方法接受一个字符串并在Azure Blob Storage上创建一个文件),这就是为什么我采取这种方法的原因。 - Adam Szabo
1
这是有误导性的。例如,对于UTF-8和StreamWriter,如果您完全省略编码构造函数参数或者将new UTF8Encoding()用作参数,则会生成没有字节顺序标记的UTF-8。另一方面,如果您将参数指定为Encoding.UTF8new UTF8Encoding(true),则会得到带有BOM的UTF-8。实际上这有点棘手。所以你的第一个例子是错误的。 - Jeppe Stig Nielsen
@JeppeStigNielsen 是的,你说得对。我已经修改了我的答案。 - Peter Ritchie
@user2270404,StreamWriter使用的stream不一定需要是文件流。 - Peter Ritchie
1
在dotnet core中没有Encoding.UTF16,请使用Encoding.Unicode代替。 - Jalal
显示剩余3条评论

1
据我所知(并不确定),当你使用相关的Unicode编码器之一将其转换为字节时,BOM会被添加。我相信其中一些构造函数需要一个布尔值来控制是否添加BOM。

1
虽然这个链接可能回答了问题,但最好在这里包含答案的关键部分,并提供链接作为参考。仅有链接的答案如果链接页面发生变化,可能会变得无效。- 来自审核 - undefined
@Ouroborus,我已经进行了修改,这样应该解决了,希望可以吧? - undefined

0

我在ASP.NET Core中使用了这段代码,效果非常好!

 [HttpGet("GetCsv")]
    public async Task<IActionResult> GetCsv() {
        
        var cc = new CsvConfiguration(new System.Globalization.CultureInfo("en-US"));
        var entity = await _service.AdminPanelList();
        using (var ms = new MemoryStream()) {
            using (var sw = new StreamWriter(stream: ms, encoding: new UTF8Encoding(true))) {
                using (var cw = new CsvWriter(sw, cc)) {

                    var bom = '\uFEFF'.ToString();
                    byte[] bomArray = Encoding.UTF8.GetBytes(bom);
                    
                    ms.Write(bomArray);
                    cw.WriteRecords(entity);
                }

                var finalArray = ms.ToArray();
                



                var result = File(finalArray, "text/csv", $"PersonExport.csv");
                    

                return result;
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接