我正在以编程方式将数据(使用PHP 5.2)导出到.csv测试文件中。
示例数据:( Numéro 1
注意带重音符号的e)。数据为utf-8
(无前置BOM)。
当我在MS Excel中打开此文件时,显示为Numéro 1
。
我可以在正确显示它的文本编辑器(UltraEdit)中打开它。UE报告该字符为decimal 233
。
如何导出 .csv文件中的文本数据,以便MS Excel正确呈现文本数据(最好不强制使用导入向导或非默认向导设置)?
我正在以编程方式将数据(使用PHP 5.2)导出到.csv测试文件中。
示例数据:( Numéro 1
注意带重音符号的e)。数据为utf-8
(无前置BOM)。
当我在MS Excel中打开此文件时,显示为Numéro 1
。
我可以在正确显示它的文本编辑器(UltraEdit)中打开它。UE报告该字符为decimal 233
。
如何导出 .csv文件中的文本数据,以便MS Excel正确呈现文本数据(最好不强制使用导入向导或非默认向导设置)?
Answers:
格式正确的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的“导入向导”实际上并不总是适用于所有编码,无论您说什么。</ anecdotal-evidence> :)

第一个单元格中的字符;或完全其他的东西。

)。它仅有助于猜测算法,以及有助于专门考虑算法的文件格式(例如XML)。在UTF-8文件中包含仿造BOM的缺点是,您破坏了它们的ASCII兼容性(UTF-8的主要卖点)。许多对编码无知的文本工具都会遇到意想不到的领先仿造BOM。
在我之前安装BOM(\ uFEFF)对我有用(Excel 2007),因为Excel将该文件识别为UTF-8。否则,可以保存它并使用导入向导有效,但是不太理想。
\ufeff
是UTF-16(BE)BOM而不是UTF-8 BOM
以下是将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
'Content-Disposition: attachment; filename="'.$filename.'.csv"'
因为Firefox需要双引号,否则它将在空格后切断文件名。
text/csv
)但将其称为Excel(application/vnd.ms-excel
)?
header('Content-Length: '. mb_strlen($encoded_csv, 'UTF-16LE'));
吗?
Excel版本(2003 + 2007)和文件类型的所有组合的答案
这里的大多数其他答案仅涉及其Excel版本,并不一定会对您有帮助,因为它们的答案可能不适用于您的Excel版本。
例如,添加BOM表字符会导致自动列分隔符识别出现问题,但并非每个Excel版本都存在问题。
有3个变量确定它是否适用于大多数Excel版本:
SAP的坚忍者尝试了每种组合并报告了结果。最终结果?使用带有BOM表和制表符的UTF16le作为分隔符,可以在大多数Excel版本中使用它。
你不相信我吗?我不会,但是请在这里阅读并哭泣:http : //wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator
sep=,
或使用任何您想使用的东西呢?如果您已经添加了BOM表,那么我想您不反对在文件中添加内容。
在输出CSV数据之前回显UTF-8 BOM。这可以修复Windows中的所有字符问题,但不适用于Mac。
echo "\xEF\xBB\xBF";
它对我有用,因为我需要生成一个仅在Windows PC上使用的文件。
UTF-8在Office 2007中在没有任何Service Pack,带或不带BOM(U + ffef或0xEF,0xBB,0xBF均不起作用)的情况下不适用于我,当0xEF,0xBB,0xBF BOM为0时,安装sp3可使UTF-8工作前置。
当使用“ utf-16-le”(带有0xff 0xef BOM前缀)并使用制表符作为分隔符在python中进行编码时,UTF-16可以工作。我必须手动写出BOM表,然后使用“ utf-16-le”而不是“ utf-16”,否则,每个encode()都会在写出的每一行之前添加BOM表,在行的第一列上显示为垃圾第二行及之后。
因为我现在不能返回,所以无法确定UTF-16是否可以在没有安装任何sp的情况下工作。叹
这是在Windows上,关于MAC Office的问题。
对于这两种情况,导入都可以在直接从浏览器启动下载时进行,并且文本导入向导不会相互干扰,就像您期望的那样。
正如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
%>
我还注意到,该问题已在一段时间前“得到解答”,但我不理解那些无法使用文本向导无法在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),显示如预期。
open('oldmac.csv', 'rb').read()
验证您的输入?
您可以保存带有扩展名'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>
border="1"
表格添加到表格中,则确实会获得行,但仅在4个单元格周围:)
这只是字符编码的问题。似乎您将数据导出为UTF-8:UTF-8中的é是两个字节的序列0xC3 0xA9,在Windows-1252中解释为é。将数据导入Excel时,请确保告诉您所使用的字符编码为UTF-8。
CSV格式在Excel中以ASCII而非unicode的形式实现,从而破坏了变音符号。我们遇到了同样的问题,这就是我如何跟踪官方CSV标准在Excel中定义为基于ASCII的问题。
我只能使CSV在Excel 2007中正确地解析为以正确的字节顺序标记开头的制表符分隔的little-endian UTF-16。
在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谢谢大家!
printWriter.print('\ufeff')
,另请参阅如何在java中添加UTF-8 BOM。
我发现的另一种解决方案是将结果编码为Windows Code Page 1252(Windows-1252或CP1252)。例如,可以通过Content-Type
适当地设置为类似的东西text/csv; charset=Windows-1252
并类似地设置响应流的字符编码来完成此操作。
检查生成文件的编码,以使excel正确显示文件,您必须使用系统默认代码页。
您使用的是哪种语言?如果是.Net,则在生成文件时只需要使用Encoding.Default。
如果像我一样在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()
我找到了解决问题的方法。这是一个令人讨厌的骇客,但是它可以起作用:使用Open Office打开文档,然后将其保存为任何excel格式;结果.xls
或.xlsx
将显示突出的字符。
使用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]