2011-07-25 66 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的文件描述符的模式。谢谢! –