Ошибка OutOfMemory при шифровании

#java #android #encryption #out-of-memory

#java #Android #шифрование #нехватка памяти

Вопрос:

Во-первых, это ошибка, которую я получаю

    java.lang.OutOfMemoryError
at coderaustin.com.FileEncryptor.encryptFile(FileEncryptor.java:56)
at coderaustin.com.Main.onCreate(Main.java:41)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1069)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2751)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2803)
at android.app.ActivityThread.access$2300(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2136)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
  

Очевидно, я знаю, в чем ошибка, я просто не знаю, как ее избежать. Это то, что делает мое приложение,

Вы выбираете файл и нажимаете Зашифровать. Таким образом, очевидно, что оттуда он берет файл и шифрует его с помощью этого кода

 try {
    FileInputStream inFile = new FileInputStream(f.getAbsolutePath());
    FileOutputStream outFile = new FileOutputStream(f.getAbsoluteFile()   ".des");

    PBEKeySpec keySpec = new PBEKeySpec(text.toCharArray());
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
    SecretKey passwordKey = keyFactory.generateSecret(keySpec);
    byte[] salt = new byte[8];
    Random rnd = new Random();
    rnd.nextBytes(salt);
    int iterations = 100;

    PBEParameterSpec paramaterSpec = new PBEParameterSpec(salt, iterations);

    Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
    cipher.init(Cipher.ENCRYPT_MODE, passwordKey, paramaterSpec);

    outFile.write(salt);



    byte[] input = new byte[inFile.available()];

    int bytesRead;
     while ((bytesRead = inFile.read(input)) != -1)
                {
                  byte[] output = cipher.update(input, 0, bytesRead);
                   if (output != null) outFile.write(output);
               }

               byte[] output = cipher.doFinal();
               if (output != null) outFile.write(output);
               f.delete();
              inFile.close();
               outFile.flush();
               outFile.close();
  

Да, я знаю, что код довольно уродливый, но он работает. Есть предложения?

Спасибо всем 🙂

Редактировать: это строка 56

byte[] input = new byte[inFile.available()];

Ответ №1:

Странно: если файл очень большой, я мог бы понять, в чем может быть проблема. Почему вы читаете весь файл сразу вместо того, чтобы читать его небольшими порциями и обрабатывать?

РЕДАКТИРОВАТЬ: попробуйте это.

 byte[] input = new byte[4096];

    int bytesRead;
     while ((bytesRead = inFile.read(input, 0, 4096)) != -1)
                {
                  byte[] output = cipher.update(input, 0, bytesRead);
                   if (output != null) outFile.write(output);
               }
  

Комментарии:

1. Вау, я чувствую себя глупо, это действительно хороший момент (и очевидный, который я должен был увидеть). Итак, какой был бы мой лучший вариант здесь? Кстати, спасибо за помощь.

2. Имейте в виду, что размеры кучи приложений Android ограничены (обычно 16 или 24 МБ), поэтому любой файл большего размера будет проблемой, даже если у вас есть сотни мегабайт свободной памяти.

3. Спасибо, что отлично сработало, и @sargas Это должно исправить это, даже если у них всего 16 или 24 мб размера кучи, верно? Поскольку вы загружаете только 4096 байт.

4. @Austin: Я бы увеличил размер буфера здесь до 64 кб или около того, просто потому, что больший буфер будет работать несколько быстрее. Конечно, идеей может быть тестирование, чтобы выяснить, где находится точка уменьшения отдачи от размера буфера.

5. Или используйте класс CipherOutputStream с BufferedOutputStream, который делает почти все за вас.