2011-07-25 12 views
15

Mam witrynę, która musi szyfrować i przechowywać pliki binarne, które są przesyłane na serwer. Na załadowanie i przechowywanie działa dobrze, ale ja dostaję ten błąd podczas próby zapisu zaszyfrowany plik:Kodowanie :: UndefinedConversionError podczas zapisu pliku binarnego

Kodowanie :: UndefinedConversionError ("\ xDD" ASCII-8bit na UTF-8):

Kod, który powoduje, że wygląda to tak:

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 

linia, która powoduje, że błąd jest file_out < < cipher.update (fragment) w pętli while. Sprawdziłem to w Internecie i znalazłem kilka raportów o podobnych problemach z konwersją ASCII/UTF, ale wszystkie wydają się być oparte na wymuszaniu wprowadzania ciągów, a nie wprowadzaniu strumienia danych. Używam Ruby 1.9.2, która, jak sądzę, wpływa na domyślne kodowanie ciągów znaków.

Moje uzasadnienie, dlaczego (myślę) potrzebuję użyć podejścia opartego na strumieniu: pliki wydają się być duże i nie chcę załadować całego pliku (wejścia lub wyjścia) do pamięci, aby go przetworzyć.

Każda pomoc jest doceniana. Dzięki.

+0

Odkryłem, że używanie .force_encoding ("UTF-8") w sprawie połączeń #update i #final rozwiązuje ten problem. Jeśli ktokolwiek może rozważyć, czy jest to właściwy sposób, i czy (dlaczego?) UTF-8 jest akceptowalny, chciałbym to wiedzieć. –

+0

Dla tego, co jest warte, sprawdziłem również Encoding.default_external i Encoding.default_internal i oba są UTF-8. –

Odpowiedz

27

Co chcesz zrobić, gdy en/deszyfrowanie traktuje wejście i wyjście jako surowe bajty, chcesz uniknąć transkodowania spowodowanego powiązaniem kodowania z danymi za wszelką cenę. Dlatego powinieneś otwierać swoje pliki w trybie binarnym, zarówno do czytania, jak i do pisania.

Właściwie zrobiłeś to, ale z IO # sysopen, ale wtedy nie przeszedłeś flag "b", gdy używasz IO # open.

Twój kod powinien działać, jeśli raczej spróbuj tego:

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

Ah - Założono (niepoprawnie), że IO # open użyje trybu deskryptora pliku z #sysopen. Dzięki! –

Powiązane problemy