2013-07-11 64 views

回答

4

這應該工作:

Dir["#{File.dirname(__FILE__)}/data/**/*.json"].each do |f| 
    begin 
    data = open(f, "r:utf-16:utf-8") {|fp| fp.read } 
    open(f, "w") {|fp| fp << data } 
    rescue Encoding::InvalidByteSequenceError 
    # Source data isn't in UTF-16, so skip this file. 
    next 
    end 
end 

總的想法是,我們打開該文件爲UTF-16,它讀入一個UTF-8編碼的字符串,然後將它寫回(如UTF-8) 。傳遞到IO.open的編碼參數自動處理轉換。

2

這產生了一些樣品的測試數據:

# encoding: UTF-8 
require 'json' 

foo = {'a'=>%w[a b ç ∂]} 
JSON.dump(foo, File.new('filein.json', 'w:UTF-16')) 

「filein.json」 是這樣的,當我cat它:

��{"a":["a","b","�","""]} 

創建後,無論是這些似乎工作:

File.open('fileout.json', 'w:UTF-8') do |fo| 
    File.open('filein.json', 'rb:UTF-16') do |fi| 
    fo.write(fi.read) 
    end 
end 

這只是一個立即寫入讀入內存;它不可擴展,但合理大小的文件應該處理好。輸入讀取爲UTF-16,輸出寫入UTF-8。

JSON.dump(
    JSON.load(File.open('filein.json', 'rb:UTF-16')), 
    File.open('fileout.json', 'w:UTF-8') 
) 

這和前面的例子很相似,但是它讓JSON gem解碼然後重新編碼文件。這可能是有用的,或者它可能不會。而且,再次,它不可擴展,因爲讀取將文件加載到內存中。

對於BIG文件超出內存,或者如果你只想做正確的事,並使用代碼的可擴展,用途:

File.open('fileout.json', 'w:UTF-8') do |fo| 
    File.foreach('filein.json', $/, encoding: 'UTF-16', mode: 'rb') do |li| 
    fo.write(li) 
    end 
end 

輸出「fileout.json」在上述所有情況下創建是:

{"a":["a","b","ç","∂"]} 

要使用Dir[]進行搜索,通過包裝他們這樣修改任何的例子:

Dir[File.dirname(__FILE__) + '/data/**/*.json'].each do |filein| 
    File.open(filein + '.new', 'w:UTF-8') do |fo| 
    File.foreach(filein, $/, encoding: 'UTF-16', mode: 'rb') do |li| 
     fo.write(li) 
    end 
    end 
end 

對於每個輸入文件,這將生成一個免費的「.json.new」文件。立即覆蓋舊文件是不安全的,因此運行後您可以根據需要重命名*.new文件。我會用:

Dir[File.dirname(__FILE__) + '/data/**/*.json'].each do |filein| 
    new_file = "#{ filein }.new" 
    File.open(new_file, 'w:UTF-8') do |fo| 
    File.foreach(filein, $/, encoding: 'UTF-16', mode: 'rb') do |li| 
     fo.write(li) 
    end 
    end 
    File.mv(filein, "#{ filein }.bak") 
    File.mv(new_file, filein) 
end