196

我正在以编程方式将数据(使用 PHP 5.2)导出到 .csv 测试文件中。
示例数据:( Numéro 1注意带重音的 e)。数据是utf-8(没有前置 BOM)。

当我在 MS Excel 中打开此文件时,显示为Numéro 1.

我可以在正确显示它的文本编辑器(UltraEdit)中打开它。UE 报告字符为decimal 233.

如何在 .csv 文件中导出文本数据,以便MS Excel 正确呈现它,最好不强制使用导入向导或非默认向导设置?

4

22 回答 22

255

格式正确的 UTF8 文件可以将字节顺序标记作为其前三个八位字节。这些是十六进制值 0xEF、0xBB、0xBF。这些八位字节用于将文件标记为 UTF8(因为它们与“字节顺序”信息无关)。1 如果此 BOM 不存在,则留给消费者/读者来推断文本的编码类型。不支持 UTF8 的阅读器会将字节作为其他编码(例如 Windows-1252)读取,并在文件开头显示字符。

有一个已知错误,即 Excel 在通过文件关联打开 UTF8 CSV 文件时假定它们采用单字节编码,而忽略UTF8 BOM 的存在。任何系统默认代码页或语言设置都无法解决问题。BOM 不会在 Excel 中提供线索 - 它只是行不通。(少数报告声称 BOM 有时会触发“导入文本”向导。)此错误似乎存在于 Excel 2003 及更早版本中。大多数报告(在此处的答案中)说这已在 Excel 2007 及更高版本中修复。

请注意,您始终可以使用“导入文本”向导在 Excel 中正确打开 UTF8 CSV 文件,该向导允许您指定正在打开的文件的编码。当然,这不太方便。

此答案的读者很可能处于他们不特别支持 Excel < 2007,但将原始 UTF8 文本发送到 Excel 的情况下,这会误解它并将您的文本洒上Ã其他类似的 Windows-1252 字符。 添加 UTF8 BOM 可能是您最好和最快的解决方法。

如果您在旧版 Excel 上遇到用户问题,并且 Excel 是 CSV 的唯一使用者,您可以通过导出 UTF16 而不是 UTF8 来解决此问题。Excel 2000 和 2003 将正确双击打开这些。(其他一些文本编辑器可能会遇到 UTF16 问题,因此您可能需要仔细权衡您的选择。)


* 除非你不能,(至少)Excel 2011 for Mac 的导入向导实际上并不总是适用于所有编码,不管你告诉它什么。</轶事证据> :)

于 2008-09-30T21:30:17.317 回答
42

预先添加 BOM (\uFEFF) 对我有用 (Excel 2007),因为 Excel 将文件识别为 UTF-8。否则,保存它并使用导入向导可以,但不太理想。

于 2008-11-24T17:11:18.583 回答
33

以下是我在向用户发送 Microsoft Excel 时在项目中使用的 PHP 代码:

  /**
   * Export an array as downladable Excel CSV
   * @param array   $header
   * @param array   $data
   * @param string  $filename
   */
  function toCSV($header, $data, $filename) {
    $sep  = "\t";
    $eol  = "\n";
    $csv  =  count($header) ? '"'. implode('"'.$sep.'"', $header).'"'.$eol : '';
    foreach($data as $line) {
      $csv .= '"'. implode('"'.$sep.'"', $line).'"'.$eol;
    }
    $encoded_csv = mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
    header('Content-Description: File Transfer');
    header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="'.$filename.'.csv"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: '. strlen($encoded_csv));
    echo chr(255) . chr(254) . $encoded_csv;
    exit;
  }

更新:文件名改进和错误修复正确的长度计算。感谢TRiG@ivanhoe011

于 2009-10-30T08:50:24.100 回答
15

Excel 版本 (2003 + 2007) 和文件类型的所有组合的答案

这里的大多数其他答案仅涉及他们的 Excel 版本,不一定会对您有所帮助,因为他们的答案可能不适用于您的 Excel 版本。

例如,添加 BOM 字符会引入自动列分隔符识别问题,但并非每个 Excel 版本都会出现问题。

有 3 个变量决定它是否适用于大多数 Excel 版本:

  • 编码
  • BOM 字符存在
  • 电池分离器

SAP 的某个坚忍的人尝试了每一种组合并报告了结果。最终结果?使用带有 BOM 的 UTF16le 和制表符作为分隔符,让它在大多数 Excel 版本中工作。

你不相信我吗?我也不会,但在这里阅读并哭泣:http ://wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator

于 2013-08-22T08:26:09.377 回答
10

导入时选择 UTF-8 编码。如果您使用 Office 2007,这是您选择它的地方:在您打开文件之后。

于 2008-09-30T21:33:51.617 回答
9

在输出 CSV 数据之前回显 UTF-8 BOM。这修复了 Windows 中的所有字符问题,但不适用于 Mac。

echo "\xEF\xBB\xBF";

它对我有用,因为我需要生成一个仅在 Windows PC 上使用的文件。

于 2011-03-30T16:26:55.417 回答
7

UTF-8 在没有任何服务包的 Office 2007 中对我不起作用,无论有无 BOM(U+ffef 或 0xEF,0xBB,0xBF,均不起作用)安装 sp3 使 UTF-8 在 0xEF,0xBB,0xBF BOM 为前置。

UTF-16 在 python 中使用带有 0xff 0xef BOM 前缀的“utf-16-le”编码并使用制表符作为分隔符时有效。我必须手动写出 BOM,然后使用“utf-16-le”而不是“utf-16”,否则每个 encode() 都会将 BOM 附加到写出的每一行之前,这些行在第一列上显示为垃圾第二行及之后。

不知道 UTF-16 是否可以在没有安装任何 sp 的情况下工作,因为我现在不能回去。

这是在windows上,不知道MAC的office。

对于这两种工作情况,直接从浏览器启动下载时导入工作,并且文本导入向导不会干预,它的工作方式与您预期的一样。

于 2012-02-18T00:03:28.023 回答
4

正如 Fregal 所说,\uFEFF 是要走的路。

<%@LANGUAGE="JAVASCRIPT" CODEPAGE="65001"%>
<%
Response.Clear();
Response.ContentType = "text/csv";
Response.Charset = "utf-8";
Response.AddHeader("Content-Disposition", "attachment; filename=excelTest.csv");
Response.Write("\uFEFF");
// csv text here
%>
于 2009-02-27T17:29:40.663 回答
3

您可以保存扩展名为“xls”的 html 文件,并且重音符号可以使用(至少 2007 年之前)。

示例:将此(在记事本中使用另存为 utf8)另存为 test.xls:

<html>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
<table>
<tr>
  <th>id</th>
  <th>name</th>
</tr>
<tr>
 <td>4</td>
 <td>Hélène</td>
</tr>
</table>
</html>
于 2009-06-05T20:06:12.283 回答
3

我还注意到这个问题前段时间得到了“回答”,但我不明白那些说如果不使用文本向导就无法在 Excel 中成功打开 utf8 编码的 csv 文件的故事。

我的可重现体验:Old MacDonald had a farm,ÈÌÉÍØ输入记事本,按 Enter,然后另存为(使用 UTF-8 选项)。

使用 Python 显示其中的实际内容:

>>> open('oldmac.csv', 'rb').read()
'\xef\xbb\xbfOld MacDonald had a farm,\xc3\x88\xc3\x8c\xc3\x89\xc3\x8d\xc3\x98\r\n'
>>> ^Z

好的。记事本在前面放了一个BOM。

现在进入 Windows 资源管理器,双击文件名,或右键单击并使用“打开方式...”,然后弹出 Excel (2003) 并按预期显示。

于 2009-06-12T03:01:12.187 回答
1

这只是字符编码的问题。看起来您正在将数据导出为 UTF-8:UTF-8 中的 é 是两字节序列 0xC3 0xA9,在 Windows-1252 中解释为 é。当您将数据导入 Excel 时,请确保告诉它您使用的字符编码是 UTF-8。

于 2008-09-30T21:11:09.283 回答
1

CSV 格式在 Excel 中实现为 ASCII,而不是 unicode,因此会破坏变音符号。我们遇到了同样的问题,这就是我发现官方 CSV 标准在 Excel 中被定义为基于 ASCII 的方式。

于 2008-09-30T21:30:01.077 回答
1

Excel 2007 正确读取带有 BOM (EF BB BF) 编码的 csv 的 UTF-8。

Excel 2003(可能更早)使用 BOM (FF FE) 读取 UTF-16LE,但使用制表符而不是逗号或分号。

于 2009-11-05T09:56:03.233 回答
1

我只能让 CSV 在 Excel 2007 中正确解析为制表符分隔的 little-endian UTF-16,从正确的字节顺序标记开始。

于 2009-12-09T13:22:14.920 回答
1

在 Django 中,将 BOM 写入输出 CSV 文件实际上对我有用:

def handlePersoonListExport(request):
    # Retrieve a query_set
    ...

    template = loader.get_template("export.csv")
    context = Context({
        'data': query_set,
    })

    response = HttpResponse()
    response['Content-Disposition'] = 'attachment; filename=export.csv'
    response['Content-Type'] = 'text/csv; charset=utf-8'
    response.write("\xEF\xBB\xBF")
    response.write(template.render(context))

    return response

欲了解更多信息http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html谢谢大家!

于 2011-05-26T13:16:14.040 回答
1

我发现的另一个解决方案是将结果编码为 Windows 代码页 1252(Windows-1252 或 CP1252)。这可以通过例如Content-Type适当地设置为类似的东西text/csv; charset=Windows-1252并类似地设置响应流的字符编码来完成。

于 2011-10-19T15:44:32.823 回答
1

请注意,包含 UTF-8 BOM 不一定是个好主意 - Mac 版本的 Excel 会忽略它,实际上会将 BOM 显示为 ASCII……电子表格第一个字段开头的三个讨厌的字符……</p>

于 2012-07-20T04:26:02.163 回答
0

检查您生成文件的编码,要使 excel 正确显示文件,您必须使用系统默认代码页。

您使用哪种语言?如果是 .Net,您只需要在生成文件时使用 Encoding.Default。

于 2008-09-30T21:12:25.613 回答
0

使用 Ruby 1.8.7,我将每个字段编码为 UTF-16 并丢弃 BOM(也许)。

以下代码是从 active_scaffold_export 中提取的:

<%                                                                                                                                                                                                                                                                                                                           
      require 'fastercsv'                                                                                                                                                                                                                                                                                                        
      fcsv_options = {                                                                                                                                                                                                                                                                                                           
        :row_sep => "\n",                                                                                                                                                                                                                                                                                                        
        :col_sep => params[:delimiter],                                                                                                                                                                                                                                                                                          
        :force_quotes => @export_config.force_quotes,                                                                                                                                                                                                                                                                            
        :headers => @export_columns.collect { |column| format_export_column_header_name(column) }                                                                                                                                                                                                                                
      }                                                                                                                                                                                                                                                                                                                          

      data = FasterCSV.generate(fcsv_options) do |csv|                                                                                                                                                                                                                                                                           
        csv << fcsv_options[:headers] unless params[:skip_header] == 'true'                                                                                                                                                                                                                                                      
        @records.each do |record|                                                                                                                                                                                                                                                                                                
          csv << @export_columns.collect { |column|                                                                                                                                                                                                                                                                              
            # Convert to UTF-16 discarding the BOM, required for Excel (> 2003 ?)                                                                                                                                                                                                                                     
            Iconv.conv('UTF-16', 'UTF-8', get_export_column_value(record, column))[2..-1]                                                                                                                                                                                                                                        
          }                                                                                                                                                                                                                                                                                                                      
        end                                                                                                                                                                                                                                                                                                                      
      end                                                                                                                                                                                                                                                                                                                        
    -%><%= data -%>

重要的一行是:

Iconv.conv('UTF-16', 'UTF-8', get_export_column_value(record, column))[2..-1]
于 2011-10-14T08:29:31.890 回答
0

我找到了解决问题的方法。这是一个令人讨厌的 hack,但它有效:使用Open Office打开文档,然后将其保存为任何 excel 格式;结果.xlsor.xlsx将显示重音字符。

于 2011-11-28T16:35:23.427 回答
0

如果您像我一样在 vb.net 中有旧代码,则以下代码对我有用:

    Response.Clear()
    Response.ClearHeaders()
    Response.ContentType = "text/csv"
    Response.Expires = 0
    Response.AddHeader("Content-Disposition", "attachment; filename=export.csv;")
    Using sw As StreamWriter = New StreamWriter(Context.Response.OutputStream, System.Text.Encoding.Unicode)
        sw.Write(csv)
        sw.Close()
    End Using
    Response.End()
于 2011-12-13T11:06:04.090 回答
-2

使用记事本++ clic 在编码上打开文件 csv,选择转换为 UTF-8(不转换为 UTF-8(不带 BOM))保存通过双击打开的 excel 希望对 Christophe GRISON 有所帮助

于 2013-04-25T16:54:44.327 回答