2014-07-22 110 views
4
文件

我已經想出了一種方法來確定針對我通過在一個文件編碼(或至少在其一個猜測):確定編碼在紅寶石

def encoding_type(file_path) 
File.read(file_path).encoding.name 
end 

這樣做的問題是,我有一個15GB的文件,這意味着整個文件正被讀入內存。

有沒有辦法在不需要將整個文件讀入內存的情況下完成我在這種方法中所做的工作?

+0

這似乎更合適f或者。 – tokland

+0

@tokland其實,['File#read'](http://www.ruby-doc.org/core-2.1.2/IO.html#method-c-read)的行爲並不簡單。你是對的:這個問題屬於Stack Overflow。 –

+0

研究Linux ['file'](http://en.wikipedia.org/wiki/File_(command))命令如何執行此操作。並且,考慮依靠它來確定編碼。另外,看看http://stackoverflow.com/questions/805418/how-to-find-encoding-of-a-file-in-unix-via-scripts –

回答

0

你在你的問題中建議的方法將而不是做你的想法。它將簡單地將文件設置爲Encoding.default_internal編碼,可能在將其從Encoding.default_external轉碼後。這些通常都是UTF-8。在運行該代碼後,編碼總是爲Encoding.default_internal,它是而不是猜測或從實際文件中確定編碼。

如果你有一個文件,你真的不知道它是什麼編碼,你確實需要猜測。沒有辦法100%確定你已經按照作者的意圖得到了正確的結果(並且一些文件已經損壞並且混合編碼或者在任何編碼中都不合法)。

有啓發式圖書館試圖猜測(他們不會一直是正確的)。

這裏有一個我從來沒有真正使用過自己,但是我在10分鐘的搜索結果中發現的潛在主義前景:https://github.com/oleander/rchardet可能還有其他的紅寶石寶石。你也可以使用ruby system()來調用一個linux命令行實用程序,它也會嘗試這樣做,上面的人提到了Linux file命令。

如果你不想加載整個文件來測試它,你當然可以加載它的一部分。可能chardet庫會更可靠地工作得越多,但是,當然,只要閱讀先讀入文件的X個字節,然後讓chardet猜測它的編碼。

require 'chardet19' 

first1000bytes = File.read(file, 1000) 
cd = CharDet.detect(first1000bytes) 
cd.encoding 
cd.confidence 

您還可以隨時檢查,看看是否在Ruby中任何字符串是有效的編碼它的設置爲:

str.valid_encoding? 

所以,你可以簡單地去通過各種編碼的,看看它是否有效:

orig_encoding = str.encoding 

str.force_encoding("ISO-8859-1").valid_encoding? 
str.force_encoding("UTF-8").valid_encoding? 

str.force_enocding(orig_encoding) # put it back to what it was 

但它肯定可能一個文件是有效的一個以上的編碼,或在給定的編碼有效,但通過在編碼人類閱讀無稽之談。

如果你有你最好的猜測編碼,但它仍然不是valid_encoding?那個編碼,它可能只是有一些壞字節。您可以使用ruby 2.1中的String.scrub或其他ruby版本中的pure-ruby backport of String.scrub刪除它們。

希望這可以幫助您瞭解您正在處理的內容以及您的選擇。

0

您可以使用​​gem和文件系統級命令嘗試獲取文件編碼。

在OSX和Linux上,file -i命令將返回該文件的MIME類型和編碼:

file -i myfile

myfile: text/plain; charset=iso-8859-1

的唯一的事情是,Mac OSX使用大寫-I相反,所以這裏有一種方法來嘗試和確定字符集...

require 'os'  
def detect_charset(file_path) 
    charset = if OS.mac? 
    `file -I #{file_path}`.strip.split('charset=').last 
    elsif OS.linux? 
    `file -i #{file_path}`.strip.split('charset=').last 
    else 
    nil 
    end 
rescue => e 
    Rails.logger.warn "Unable to determine charset of #{file_path}" 
    Rails.logger.warn "Error: #{e.message}" 
end