Excel CSV 编码问题

Fre*_*erg 2 c# encoding asp.net-core

我有关于丹麦语字符的问题,并在 Excel 中打开保存为 CSV 的文件。请参阅下面的代码:

\n\n
        [HttpGet]\n        [Route("/progress/data.csv")]\n        [Produces("text/csv")]\n        public IActionResult GetCSV()\n        {\n            StringBuilder sb = new StringBuilder();\n            sb.AppendLine("\xc3\xa6\xc3\xb8;2;3;");\n            Encoding encode = Encoding.UTF8;\n            return File(encode.GetBytes(sb.ToString()), "text/csv", "data.csv");\n        }\n
Run Code Online (Sandbox Code Playgroud)\n\n

我使用的是 .NET Core 2.1,此导出的结果是前两个字符 \xc3\xa6\xc3\xb8 显示为 \xc3\x83\xc2\xa6\xc3\x83 。

\n\n

我知道这是一个已知问题,但到目前为止我还没有找到解决方案。在过去的 4 个小时里,我尝试了至少 15 种不同的方法,包括带/不带 BOM 的 UTF。使用 System.Text.Encoding.UTF8.GetPreamble() 手动添加 BOM,各种 MemoryStream、StreamWriter 解决方案,尝试使用 windows-1252 和 CodePagesEncodingProvider.Instance.GetEncoding(1252) 但没有任何效果。当在 Excel 中打开此文件时,结果总是与预期不同。

\n\n

有人对此有解决方案吗?

\n

itm*_*nus 5

嗯,问题出在Excel处理BOM的方式上。您可能会发现使用StreamWriter

\n\n
\n

除非另有指定,否则 StreamWriter 默认使用 UTF8Encoding 的实例。UTF8Encoding 的此实例是在没有字节顺序标记 (BOM) 的情况下构造的,因此其 GetPreamble 方法返回一个空字节数组。此构造函数的默认 UTF-8 编码会在无效字节上引发异常。此行为与 Encoding.UTF8 属性中的编码对象提供的行为不同。要指定 BOM 并确定是否对无效字节引发异常,请使用接受编码对象作为参数的构造函数,例如 StreamWriter(String, Boolean, Encoding) 或 StreamWriter。

\n
\n\n

所以我只是创建一个自定义实现IActionResult

\n\n
public class Utf8ForExcelCsvResult : IActionResult\n{\n    public string Content{get;set;}\n    public string ContentType{get;set;}\n    public string FileName {get;set;}\n    public Task ExecuteResultAsync(ActionContext context)\n    {\n        var Response =context.HttpContext.Response;\n        Response.Headers["Content-Type"] = this.ContentType;\n        Response.Headers["Content-Disposition"]=$"attachment; filename={this.FileName}; filename*=UTF-8\'\'{this.FileName}";\n        using(var sw = new StreamWriter(Response.Body,System.Text.Encoding.UTF8)){\n            sw.Write(Content);\n        }\n        return Task.CompletedTask ;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当您需要使用 Excel 打开此类 csv 文件时,只需返回Utf8ForExcelCsvResult.

\n\n
[HttpGet]\n[Route("/progress/data.csv")]\n[Produces("text/csv")]\npublic IActionResult MyFileDownload()\n// public Utf8ForExcelCsvResult MyFileDownload()\n{\n    StringBuilder sb = new StringBuilder();\n    sb.AppendLine("\xc3\xa6\xc3\xb8;2;3;");\n    sb.AppendLine("\xe1\x83\x92\xe1\x83\x90\xe1\x83\x9b\xe1\x83\x90\xe1\x83\xa0\xe1\x83\xaf\xe1\x83\x9d\xe1\x83\x91\xe1\x83\x90");\n    sb.AppendLine("\xe1\x80\x9f\xe1\x80\x9a\xe1\x80\xba\xe1\x80\x9c\xe1\x80\xad\xe1\x80\xaf");\n    sb.AppendLine("\xe0\xba\xaa\xe0\xba\xb0\xe0\xba\x9a\xe0\xba\xb2\xe0\xba\x8d\xe0\xba\x94\xe0\xba\xb5");\n    sb.AppendLine("cze\xc5\x9b\xc4\x87");\n    sb.AppendLine("\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf");\n    sb.AppendLine("\xe4\xbd\xa0\xe5\xa5\xbd");\n    Console.WriteLine(sb.ToString());\n    return new Utf8ForExcelCsvResult(){\n        Content=sb.ToString(),\n        ContentType="text/csv",\n        FileName="hello.csv",\n    };\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在此输入图像描述

\n\n

我们可以使用 Powershell 通过以下方式检查 csv 文件的十六进制表示形式Format-hex -path .\\hello.csv

\n\n
           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000000   EF BB BF C3 A6 C3 B8 3B 32 3B 33 3B 0D 0A E1 83  \xc3\xaf\xc2\xbb\xc2\xbf\xc3\x83\xc2\xa6\xc3\x83\xc2\xb8;2;3;..\xc3\xa1\n00000010   92 E1 83 90 E1 83 9B E1 83 90 E1 83 A0 E1 83 AF  \xc3\xa1\xc3\xa1\xc3\xa1\xc2\xa0\xc3\xa1\xc2\xaf\n00000020   E1 83 9D E1 83 91 E1 83 90 0D 0A E1 80 9F E1 80  \xc3\xa1\xc3\xa1\xc3\xa1..\xc3\xa1\xc3\xa1\n00000030   9A E1 80 BA E1 80 9C E1 80 AD E1 80 AF 0D 0A E0  \xc3\xa1\xc2\xba\xc3\xa1\xc3\xa1\xc2\xad\xc3\xa1\xc2\xaf..\xc3\xa0\n00000040   BA AA E0 BA B0 E0 BA 9A E0 BA B2 E0 BA 8D E0 BA  \xc2\xba\xc2\xaa\xc3\xa0\xc2\xba\xc2\xb0\xc3\xa0\xc2\xba\xc3\xa0\xc2\xba\xc2\xb2\xc3\xa0\xc2\xba\xc3\xa0\xc2\xba\n00000050   94 E0 BA B5 0D 0A 63 7A 65 C5 9B C4 87 0D 0A E3  \xc3\xa0\xc2\xba\xc2\xb5..cze\xc3\x85..\xc3\xa3\n00000060   81 93 E3 82 93 E3 81 AB E3 81 A1 E3 81 AF 0D 0A  \xc3\xa3\xc3\xa3\xc2\xab\xc3\xa3\xc2\xa1\xc3\xa3\xc2\xaf..\n00000070   E4 BD A0 E5 A5 BD 0D 0A                          \xc3\xa4\xc2\xbd\xc2\xa0\xc3\xa5\xc2\xa5\xc2\xbd..\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里前三个字节EF BB BF字节顺序标记

\n