2011-07-25 157 views
15

我有一個網站需要加密和存儲上傳到服務器的二進制文件。上傳和存儲工作正常,但我得到試圖寫加密的文件時,這個錯誤:編寫:: UndefinedConversionError編寫二進制文件

編碼:: UndefinedConversionError( 「\的xDD」 從ASCII-8BIT爲UTF-8):

,導致它看起來像這樣的代碼:

fd_in = IO.sysopen(self[:name].tempfile.path, "rb")       
file_in = IO.open(fd_in)              
fd_out = IO.sysopen(self[:name].tempfile.path + ".encrypted", "wb")   
file_out = IO.open(fd_out)              
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')       
cipher.encrypt                           
cipher.key = cipher_key              
cipher.iv = cipher_iv              
while chunk = file_in.read(1024)            
    file_out << cipher.update(chunk)            
end 
file_out << cipher.final 

導致該錯誤是在while循環的file_out < < cipher.update(塊)的線。我在網上查了一下,發現了一些類似ASCII/UTF轉換問題的報告,但它們似乎都是基於強制字符串輸入而不是流文件輸入。我使用的是Ruby 1.9.2,我認爲這會影響默認的字符串編碼。

我的理由是爲什麼(我認爲)我需要使用基於流的方法:文件往往很大,我不想將整個文件(輸入或輸出)加載到內存中進行處理。

任何幫助表示讚賞。謝謝。

+0

我發現,使用.force_encoding(「UTF-8」)的#UPDATE和#final電話解決問題。如果任何人都可以權衡這是否是正確的做法,如果(爲什麼?)UTF-8可以接受,我很想知道。 –

+0

對於它的價值,我也檢查了Encoding.default_external和Encoding.default_internal,兩者都是UTF-8。 –

回答

27

當en-/decrypting將輸入和輸出視爲原始字節時,您想要執行的操作是,避免因不惜代價將編碼與數據關聯而導致的任何轉碼。所以你應該以二進制模式打開你的文件,無論是閱讀還是寫作。

其實你已經這樣做了,但是用IO#sysopen,但是當你使用IO#打開時你沒有通過「b」標誌。

您的代碼應該工作,如果你願意嘗試這個辦法:

fin = File.open("TODO", "rb")       
fout = File.open("TODO.encrypted", "wb")   
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc') 
cipher.encrypt      
cipher.key = key              
cipher.iv = iv              
while chunk = fin.read(1024)            
    fout << cipher.update(chunk)            
end 
fout << cipher.final 
fin.close 
fout.close 
+0

啊 - 我認爲(錯誤地)IO#打開將使用來自#sysopen的文件描述符的模式。謝謝! –