将UTF8数据导出到Excel的最佳方式是什么?

将UTF8数据导出到Excel的最佳方式是什么?

问题描述:

所以我们有这个Web应用程序,我们支持UTF8数据。 Hooray UTF8。而且我们可以将用户提供的数据导出为CSV,这一点没有问题 - 在这一点上它仍然是UTF8。问题是,当你在Excel中打开一个典型的UTF8 CSV文件时,它将其读取为ANSII编码的文本,并相应地尝试读取ø和ü这样的两个字节的字符作为两个独立的字符,并最终导致失败。将UTF8数据导出到Excel的最佳方式是什么?

所以我做了一些挖掘(间隔人员有一个有趣的职位about it here),并有一些有限的,如果可笑的恼人的选择那里。其中:

  • 提供一个UTF-16小端TSV文件,Excel将正确解释,但不支持多行数据
  • 在HTML表格中使用Excel MIME类型提供的数据或文件扩展名(不确定此选项是否支持UTF8)
  • 有几种方法可以将XML数据导入到各种最新版本的Excel中,理论上这些将支持UTF8。 SpreadsheetML,使用自定义XSLT或通过模板生成新的Excel XML格式。

看起来无论如何,我可能会继续为那些不使用Excel的人提供一个普通的CSV文件,并为Excel单独下载选项​​。

什么是生成Just-For-Excel文件的最简单方法,它将正确支持UTF8,我亲爱的Stack Overflowers?如果这个最简单的选项只支持最新版本的Excel,那还是很有趣的。

我正在Rails堆栈上做这件事,但好奇的是.Net-ers和任何框架上的人如何处理这个问题。我自己在几个不同的环境中工作,这绝对是一个将再次成为问题的问题。

更新2010-10-22:我们在我们的时间跟踪系统Tempo中使用了Ruport gem,以便在我首次发布此问题时提供CSV导出。我的一个同事,埃里克Hollensbee,一起扔了一个快速过滤器Ruport为我们提供了实际的Excel XSL输出,我想我会分享,在这里任何其他红宝石派:

require 'rubygems' 
require 'ruport' 
require 'spreadsheet' 
require 'stringio' 

Spreadsheet.client_encoding = "UTF-8" 

include Ruport::Data 

class Ruport::Formatter::Excel < Ruport::Formatter 
    renders :excel, :for => Ruport::Controller::Table 

    def output 
    retval = StringIO.new 

    if options.workbook 
     book = options.workbook 
    else 
     book = Spreadsheet::Workbook.new 
    end 

    if options.worksheet_name 
     book_args = { :name => options.worksheet_name } 
    else 
     book_args = { } 
    end 

    sheet = book.create_worksheet(book_args) 

    offset = 0 

    if options.show_table_headers 
     sheet.row(0).default_format = Spreadsheet::Format.new(
     options.format_options || 
     { 
      :color => :blue, 
      :weight => :bold, 
      :size => 18 
     } 
    ) 
     sheet.row(0).replace data.column_names 
     offset = 1 
    end 

    data.data.each_with_index do |row, i| 
     sheet.row(i+offset).replace row.attributes.map { |x| row.data[x] } 
    end 

    book.write retval 
    retval.seek(0) 
    return retval.read 
    end 
end 

你忘记创建OleDB数据源和Excel Interop,但也存在这些问题。

我推荐SpreadsheetML选项。它工作得很好,很可能你的平台有一些体面的工具来构建xml文件,并且早在OfficeXP中就已经完全支持它。 Office2000不受支持,但个人经验是它以有限的方式工作。

+0

“你忘了......一个OLEDB ......” 嘘!这是一个unix环境,所以我想避免那种Voodoo。谢谢你的提示! – 2009-01-16 19:49:06

+1

那为什么它被标记为正确? – hoju 2012-04-03 13:53:37

+0

@理查德 - 因为第二段,它不依赖oledb。虽然从1年半后发布的更新中,应该有一个答案,在这里指向人们Ruby Rubpert。 – 2012-04-03 13:54:59

如果创建一个UTF编码的XML并保存为.xls的它会打开即使是两个字节的字符:

XML版本= “1.0” 编码= “UTF-8”

+0

我确实尝试保存带有扩展名.xls的表格数据的XML文档,然后使用Excel for Mac 2003打开它,并且只是将它放在上面。我们有相当数量的用户是Mac用户。 – 2009-01-16 19:54:50

+1

我从来没有尝试与MAC,但它应该工作,XML是一个标准 – Rulas 2009-01-17 05:33:44

+0

@BillyGray什么样的错误是'barfed'? – gcb 2011-10-20 22:00:17

我有将UTF8数据发送到Excel的问题。我的解决方案:

当前版本的Perl Spreadsheet :: WriteExcel cpan代码正确地使用UTF8数据写入Excel文件。

所以我写了一个Rails插件,它可以:a)打开一个双向管道到perl程序 b)每次向perl程序发送一行数据。我使用Yaml作为消息数据格式。 (标准Ruby yaml不是UTF8,有特殊版本可用,ya2yaml) c)perl程序创建excel文件 d)当Rails程序指示(通过yaml消息)最后一行已发送时,perl程序创建excel文件并将状态发回到rails程序。

当然,通过并行进程和管道将perl程序添加到rails项目中,在“工程”谱中非常多,而不是“计算机科学”。 (它完成了工作,但并不优雅。)但它工作得很好,为我节省了将WriteExcel代码移植到Ruby所需的时间。另请注意,当前可用的WriteExcel Ruby端口不处理utf8。

我的sw是宽容的开源,但我还没有到处发布它呢。如果你想要它在目前的状态,请参阅http://sandbox.kluger.com/write_excel_v.5.tar

请注意,您将需要在后台进程中创建您的excel文件,而不是在Rails控制器的进程中,因为这会在您磨掉时拦截其他浏览器客户端生成excel文件。我使用DelayedJob插件,效果很好。

希望这有助于

拉里

尝试OpenOffice的计算器 - 它更Unicode的友好 - 无论是导入和导出CSV文件使用UTF-8编码。

同样的问题挣扎了几个小时后,我发现关于这个问题的这个优秀的帖子

http://blog.plataformatec.com.br/2009/09/exporting-data-to-csv-and-excel-in-your-rails-app/ 报价:

所以,这些都是 的三个规则处理与Excel友好-CSV:

  1. 使用表格,而不是逗号。
  2. 字段不能包含换行符。
  3. 使用UTF-16 Little Endian将文件发送给用户。并手动添加 Little Endian BOM。

不过,如果你使用的红宝石,你的问题就解决了: 首先,你必须在FasterCSV宝石

但我结束了使用电子表格的宝石直接生成EXCELL表格 (我有链接限制,只是谷歌电子表格+ ruby​​forge) 辉煌!

Excel无法正确处理UTF-8。 你应该使用一个代码页,能满足您的需求

Response.ContentType = "text/plain"; 
// codepage: 28591, codepage name:iso-8859-1, codepage display name: Western European (ISO) 
Response.ContentEncoding = System.Text.Encoding.GetEncoding(28591); 

我发现,如果你设置的网页的字符集编码为UTF-8,然后响应。Binary在csv文件的顶部写入UTF-8字节顺序标记(0xEF 0xBB 0xBF),然后Excel 2007(不确定其他版本)会将其识别为utf-8并将其正确打开。

我倒在这篇文章寻找Ruby的答案,为什么Excel不会正确加载utf-8字符的CSV。摸索和试验后,该解决方案为我工作:

csv_content = CSV.generate(col_sep: "\t", headers: :first_row, encoding: 'utf-8') do |csv| 
    csv << ["header1", "header2"] 
    csv << ["content1", "content2"] 
end 
write_content = Iconv.conv("utf-16le", "utf-8", "\xEF\xBB\xBF") 
write_content += Iconv.conv("utf-16le", "utf-8", csv_content) 
File.open("listing.csv", 'wb') {|f| f.write(write_content) }