如何确保我的文件下载是UTF-8编码?(而不是带BOM的UTF-8编码)

10
我已经编写了一个下载函数,用于将消息下载到CSV文件中(代码如下)。现在当我在记事本或记事本++中打开它时,我看到的是这样的:
é NY ø ╬ ║► ░ ê ö
(顺便说一句,这就是数据库中的内容)
现在,当我在Ms-Excel中打开它时,它显示为:
é NY ø ╬ ║► ░ ê ö
当我在notepad++中打开它时,它显示为“UTF8 without BOM”编码。当我在notepad++中将其编码为UTF-8时,一切都正常(也就是说,Excel也显示正确的字符)。
但是,我该如何确保从我的代码创建的文件是UTF-8?
这是我的代码:
public ActionResult DownloadPersonalMessages()
{    
    StringBuilder myCsv = new StringBuilder();
    myCsv.Append(new DownloadService().GetPersonalMessages());

    this.Response.ContentType = "text/csv";
    Response.AddHeader("content-disposition", "attachment; filename=PersonalMessages.csv");
    Response.ContentEncoding = Encoding.UTF8;
    Response.Write(myCsv.ToString());
    Response.Flush();
    Response.HeaderEncoding = Encoding.UTF8;
    return Content("");
}

编辑:

我的函数现在返回一个ByteArray,其中包含以下转换

UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(str);

现在我的下载速度是这样的:

Response.AddHeader("Content-Disposition", "attachment; filename=PersonalMessages.csv");
return File(new DownloadService().GetPersonalMessages(), "text/csv");
3个回答

22

Zareth的回答对OP有所帮助,但实际上并没有回答问题。这里是正确的解决方案,来自这篇其他帖子

public ActionResult Download()
{
    var data = Encoding.UTF8.GetBytes("some data");
    var result = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
    return File(result, "application/csv", "foo.csv");
}

字节顺序标记(虽然在 UTF8 中不是必需的)会提示某些程序(例如 Excel 2007 及以上版本),你正在使用 UTF8。您必须通过 GetPreamble() 方法手动包含它。


MIME类型应为:text/csv请参见此处(如果您想更精确,请使用:text/csv; charset=utf-8请参见此处)。 - Ofir
@fini007:我认为这取决于意图。根据这篇SO帖子,“如果服务器说‘这个数据是text/csv类型’,客户端可以理解并在内部呈现该数据,而如果服务器说‘这个数据是application/csv类型’,客户端知道它需要启动在操作系统上注册的应用程序来打开csv文件。”如果您想让浏览器启动Excel,则“application/csv”可能更好。当然,如果您使用content-disposition使文件下载,则这有点无关紧要。 - StriplingWarrior

4

您可以尝试使用UTF8Encoding类。构造函数有一个参数,确定它是否应该提供BOM。您可能需要使用GetBytes方法,并将字符串作为响应中的一系列字节编写,而不是将其转换回.net字符串对象。


1
谢谢,我已将代码更改为System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(true);但仍然没有运气... - Michel
1
你通过getbytes的方式让我找到了正确的方向。之前我走错了路,因为notepad++说这是一个utf8而不是bom文件,当我将其转换为utf8时,它可以工作。但当然utf8并不是我的要求。我尝试使用unicodeencoding,结果它奏效了。感谢你的思考。 - Michel
1
提醒:由于某种原因,构造函数参数实际上不会导致输出 BOM。您需要手动在结果前面添加 .GetPreamble() 的返回值。 - StriplingWarrior

1

你可以简化一下你的代码:

public ActionResult DownloadPersonalMessages()
{
    StringBuilder myCsv = new StringBuilder();
    myCsv.Append(new DownloadService().GetPersonalMessages());
    Response.AddHeader("Content-Disposition", "attachment; filename=PersonalMessages.csv");
    return File(Encoding.UTF8.GetBytes(myCsv.ToString()), "text/csv");
}

就UTF-8编码而言,我担心问题可能出在这个GetPersonalMessages方法上。你可能需要返回一个流或字节数组,可以直接作为文件返回。

会尝试一下。通过尝试各种不同的方法,代码变得如此庞大 :) - Michel
嗯,当我返回一个字节数组时,它会变成UTF8吗?好的,我试一下。顺便说一下,GetPersonalMessgages()函数从数据库中读取一个nvarchar字段。 - Michel

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