Encoding:: 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
Линией, которая вызывает ошибку, является file_out < cipher.update(chunk) в цикле while. Я просмотрел этот онлайн-ресурс и нашел несколько отчетов о аналогичных проблемах преобразования ASCII/UTF, но все они, как представляется, основаны на принудительном вводе строки, а не на поточном файле. Я использую Ruby 1.9.2, который, как мне кажется, влияет на кодировку строки по умолчанию.
Мое объяснение, почему (я думаю) мне нужно использовать потоковый подход: файлы имеют тенденцию быть большими, и я не хочу загружать весь файл (ввод или вывод) в память для его обработки.
Любая помощь приветствуется. Благодарю.
Ответы
Ответ 1
Что вы хотите делать, когда en-/decrypting обрабатывает ввод и вывод как необработанные байты, вы хотите избежать любого перекодирования, вызванного связыванием кодировки с вашими данными любой ценой. Поэтому вы должны открывать свои файлы в двоичном режиме, как для чтения, так и для записи.
На самом деле вы это сделали, но с IO # sysopen, но тогда вы не передавали флаги "b" при открытии IO #.
Ваш код должен работать, если вы скорее попробуете это:
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