Ruby Ruby 保存的 csv 文件,跟 Excel 各种不对付啊……

hexawing · 2013年09月23日 · 最后由 larrylv 回复于 2013年09月23日 · 8491 次阅读

代码如下:

def self.to_csv(options = {})
    require "csv"
    require "nkf"
    field_name = ["\xEF\xBB\xBF姓名", "Name", "Birthday"]  #csv文件的头(标题)

    output = CSV.generate do |csv|
        csv << field_name
        all.each do |person|
            csv << [person.name, person.en_name, person.email]   # 将数据插入数组中
        end
    end
    fh = File.new("#{Rails.root}/public/abc.csv", "wb")  #创建一个可写文件流
    fh.puts NKF.nkf("-wL",output) #写入数据。这里没用原作者的“-wLuxs”,因为似乎结果不太对
    fh.close
end

参考的这位的写法: http://jarry-li.iteye.com/blog/1870476 存出来的 CSV 在我 Ubuntu 下的 LibreOffice Calc 打开是正常的,Windows 下用 WPS Office 打开也是正常的,但 Excel2010 2007 打开均为乱码。记事本打开再选择另存为发现编码是 UTF8,改成 ANSI 再另保存后大家打开都正常。 我也试过在文件前加上\uFEFF 出处:http://blog.sammylin.tw/export-to-csv-has-mojibake/ 还是不行……

也就是说,Excel 不识别 utf8 的文件头,那么我怎么能让 Ruby 生成出来的文件没有任何文件头(也就是 ANSI?)呢?我去掉过\xEF\xBB\xBF,但似乎是 Ruby 默认的 utf8 的关系,所以不生效?

用 ruby2.0 应该就不需要手动加文件头了 我觉得更好的解决办法是如果需要 xls 的话就加一个输出 xls 的选项 就不要这么纠结了...

#1 楼 @zj0713001 您是指用 spreadsheet 之类的 gem 吗?

#3 楼 @LarryLv 对的,我也查到了用\t的办法,试了试,确实可以。不过也不是直接双击打开,而是要先打开 Excel,然后“数据→自文件”,才会出现那个导入向导。

def self.to_csv
    csv_string = CSV.generate(:col_sep => "\t", :row_sep => "\r\n") do |csv|
        csv << ['姓名', 'en_name', 'email']
        all.each do |r|
            csv << [r.name, r.en_name, r.email]
        end
    end

    fh = File.new("#{Rails.root}/public/abc_col_sep.csv", "wb")  #创建一个可写文件流
    fh.puts NKF.nkf("-wL",csv_string) #写入数据

    fh.close
end

#4 楼 @zj0713001 我早上还想过这个,后来查到这个帖子: http://ruby-china.org/topics/1225 于是还是想先试试 csv,哦,按那个英文作者的说法是 tsv……

#6 楼 @hexawing 如果你生成的报表是给人看的 不可能有上万条记录的 谁看啊... 如果是给接口读取的 大部分都支持 csv 的

#5 楼 @hexawing 重点是这段:Forget about UTF-8. Use UTF-16!

Wrapping up

So, these are the three rules for dealing with Excel-friendly-CSV:

  • Use tabulations, not commas.
  • Fields must NOT contain newlines.
  • Use UTF-16 Little Endian to send the file to the user. And include a Little Endian BOM manually.

#8 楼 @LarryLv 嗯,我再继续研究。十分感谢!

折腾了半天(关键是Iconv.conv"str".encode("UTF-16")这两个东东),但还是不能被 Excel 直接打开。算了,导入就导入吧……能不乱码就好=_=

#10 楼 @hexawing

比如你生成的 csv 字符串为 csv_string (编码为 utf-8).

那么在最后写入文件时,只要在文件头加上 Byte order mark,然后将字符串转换为 utf-16 little endian 编码即可。

代码大致是下面这样:

CSV_BOM = "\377\376"

require 'iconv'

class String
  def utf8_to_utf_16
    begin
      Iconv.conv('UTF-16LE', 'UTF-8', self)
    rescue
      self
    end
  end
end

File.open(file_path, "w") { |file|
  file.puts CSV_BOM + csv_string.utf8_to_utf16
}

Ruby 2.0 的话,可以

CSV.generate do|csv|
  #generating....
end.encode('gb2312', , :invalid => :replace, :undef => :replace, :replace => "?")
需要 登录 后方可回复, 如果你还没有账号请 注册新账号