2015-12-24 8 views
5

Przetestowałem mój kod z plikami mniejszymi niż ten (10 MB, 100 MB, 500 MB) i szyfrowanie działa. Jednak mam problemy z plikami powyżej 1 GB. Wygenerowałem duży plik (około 2 gb) i chcę go zaszyfrować przy pomocy AES przy użyciu JAVA, ale pojawia się następujący błąd:Szyfrowanie dużego pliku za pomocą AES przy użyciu JAVA

"Wyjątek w wątku" główny "java.lang.OutOfMemoryError: Java przestrzeń sterty "

Próbowałem zwiększyć dostępną pamięć przy użyciu -Xmx8G, ale bez kości. Część mojego kodu jest następujący

File selectedFile = new File("Z:\\dummy.txt");   
    Path path = Paths.get(selectedFile.getAbsolutePath());  
    byte[] toencrypt = Files.readAllBytes(path);  
    byte[] ciphertext = aesCipherForEncryption.doFinal(toencrypt); 
    FileOutputStream fos = new FileOutputStream(selectedFile.getAbsolutePath()); 
    fos.write(ciphertext); 
    fos.close(); 

O ile mogę powiedzieć, przyczyną tego, że zachowuje się w ten sposób, jest to, że próbuje odczytać cały plik na raz, encipher go i przechowywać go w inna tablica bajtów zamiast buforowania i przesyłania strumieniowego. Czy ktoś może mi pomóc z niektórymi poradami dotyczącymi kodu?

Jestem początkującym programistą, więc nie wiem zbyt wiele, każda pomoc zostanie doceniona.

Odpowiedz

10

Nie próbuj nawet czytać całych dużych plików do pamięci. Szyfruj bufor na raz. Po prostu wykonaj standardową pętlę kopii z odpowiednio zainicjowanym CipherOutputStream owiniętym wokół FileOutputStream. Możesz użyć tego dla wszystkich plików, bez konieczności tworzenia specjalnego przypadku. Użyj bufora 8k lub więcej.

EDIT 'standardowego kopiowania pętla' w Javie jest następujący:

byte[] buffer = new byte[8192]; 
int count; 
while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
} 

gdzie w tym przypadku out = new CipherOutputStream(new FileOutputStream(selectedFile), cipher).

+1

„Szyfrowanie bajt na raz”: Z szyfrowania Szyfry blokowe jest przez blok (AES: 16 bajtów). – zaph

+0

Po przeczytaniu odpowiedzi EJP wciąż nie jestem pewien, co oznacza "standardowa pętla kopiowania". Rozumiem, że muszę czytać dane wejściowe bajt w tym samym czasie lub w blokach. Nie jestem pewien, co zrobić z pętlą. Czy ktoś może wskazać mi kierunek poszukiwań? odniesieniu do szyfrów częścią strumienia wyjściowego z tym, powinien wyglądać tak: CipherOutputStream cos = nowy CipherOutputStream (FileOutputStream (selectedFile.getAbsolutePath()); – halcyondayz

+0

@zaph Ups, że to typo do 'buforowania' ale "Cipher" dba o rozmiar bloków bazowych dla ciebie. – EJP

1

Można również uprościć proces jeszcze dalej korzystając Encryptor4j: https://github.com/martinwithaar/Encryptor4j

File srcFile = new File("original.zip"); 
File destFile = new File("original.zip.encrypted"); 
String password = "mysupersecretpassword"; 
FileEncryptor fe = new FileEncryptor(password); 
fe.encrypt(srcFile, destFile); 

Ta biblioteka korzysta z szyfrowania strumieniowego więc nie spowoduje OutOfMemoryError nawet z dużymi plikami. Ponadto, zamiast używać haseł, możesz również użyć własnego Key.

Sprawdź przykład na stronie github tutaj: https://github.com/martinwithaar/Encryptor4j#file-encryption

Powiązane problemy