Rails 导入导出CSV数据时的中文编码问题
Posted by devon on December 12th, 2008 filed in Rails应用在Rails中导入导出数据到 Excel 时,使用CSV格式较多,但在转换各种编码时,经常出现个别字符的乱码问题,主要原因在于 utf8, gb2321, gb18030, gbk 的字符集所包含的中文字不一样,在实践中,总结出来如下的办法来做导入导出。由于在实际应用中,以 utf8 为主,这里也以 utf8 为核心来做导入导出。
导出数据
将 utf8 转为 unicode 编码,在excel 2003, 及excel 2007 中都能正确识别中文字符,而且 unicode 编码字符集大,基本无乱码现象。导出后的 csv 文件需要加BOM标记。
示例代码:
1, 在String类中增加一些转换字符集的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class String def utf8_to_gb2321 encode_convert(self, "gb2321", "UTF-8") end def gb2321_to_utf8 encode_convert(self, "UTF-8", "gb2321") end def utf8_to_utf16 encode_convert(self, "UTF-16LE", "UTF-8") end def utf8? begin utf8_arr = self.unpack('U*') true if utf8_arr && utf8_arr.size > 0 rescue false end end private def encode_convert(s, to, from) require 'iconv' begin converter = Iconv.new(to, from) converter.iconv(s) rescue s end end end |
2, 如果直接导出CSV文件,并发送到客户端,参考如下代码:
1 2 3 4 5 6 7 8 9 10 11 | def export_csv require 'fastercsv' records = Amodel.find(:all, :limit => 10) csv_string = FasterCSV.generate(:col_sep => "\t", :row_sep => "\r\n") do |csv| csv << ['field_name1', 'field_name2', 'field_name3'] records.each do |r| csv << [r.field1, r.field2, r.field3] end end send_data("FFFE".gsub(/\s/,'').to_a.pack("H*") + csv_string.utf8_to_utf16, :type => 'text/csv; charset=utf16; header=present', :filename => "exp.csv") end |
这里需要注意几点:a), 值之间使用\t标记(:col_sep),而不是通常的逗号。 b) FFFE是utf_16le的BOM标记,写在文件头,表示该文件是utf_16le编码。
3,如果直接写到csv文件(比如在一些Rake Task中),参考如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private def export_csv require 'fastercsv' records = Amodel.find(:all, :limit => 10) csv_string = FasterCSV.generate(:col_sep => "\t", :row_sep => "\r\n") do |csv| csv << ['field_name1', 'field_name2', 'field_name3'] records.each do |r| csv << [r.field1, r.field2, r.field3] end end File.open("export.csv","w") do |file| file.syswrite "FFFE".gsub(/\s/,'').to_a.pack("H*") + csv_string.utf8_to_utf16 end end |
导入数据
从CSV导入数据时,要注意编码的检测,通常情况下,用户的原始文件会以 GB2321 形式存在,这时,只需要将导入的数据从 GB2321 转换为 UTF8 即可。如果原始文件已经是 UTF8,就不再需要转换了。
1 2 3 4 5 6 7 8 | def import_to_db rows = CSV::parse(File.open("input_file.csv") {|f| f.read}) is_utf8 = rows[0].join(',').utf8? rows.each { |row| row = row.map {|v| v.gb2321_to_utf8} unless is_utf8 Amodel.create(:filed1 => row[0], :field2 => row[2], :field3 => row[3]) end end |
在转换前,探测一下文件的第一行数据是不是UTF8,如果已经是UTF8,就不再需要转换了。
扩展阅读:
GB18030, GBK, GB2321: 最早制定的汉字编码是GB2312,包括6763个汉字和682个其它符号 95年重新修订了编码,命名GBK1.0,共收录了21886个符号。 之后又推出了GBK18030编码,共收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字,现在WINDOWS平台必需要支持GBK18030编码。按照GBK18030、GBK、GB2312的顺序,3种编码是向下兼容,同一个汉字在三个编码方案中是相同的编码。
BOM: Byte Order Mark,就是字节序标记。参考官方解释
Related posts:
- 利用FastCSV将网站数据导出到csv文件 安装: sudo gem install fastercsv 具体使用看Readme,下面介绍FastCSV在导出网站数据中的应用 主函数代码如下,在关键点已经给出注释。 def export_csv(showfieldname, showfield,...
Related posts brought to you by Yet Another Related Posts Plugin.
April 21st, 2009 at 11:30 AM
thanks devon.
nice tutorial.
[Reply]