关于在an​​droid中加密大文件的java.lang.OutOfMemoryError

时间:2014-01-22 11:10:35

标签: java android out-of-memory

我正在尝试使用Android中的AES算法加密23 MB文件。虽然代码适用于文件大小约3-4 MB。但是,当我使用23 MB文件进行测试时,它会给我一个java.lang.OutOfMemoryError

这是代码 -

                 try{
                        SecretKeySpec skey = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES");
                        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                        cipher.init(Cipher.ENCRYPT_MODE, skey);
                        output = cipher.doFinal(bFile);
                        String SD_CARD_PATH = Environment.getExternalStorageDirectory().toString();
                        FileOutputStream fileOuputStream = new FileOutputStream(SD_CARD_PATH+ "/" + "abcd.db"); 
                        fileOuputStream.write(output);
                        fileOuputStream.close();
                        //System.out.println(output);
                    }catch(Exception e){
                        System.out.println("Error: "+e);
                    }

我在行中遇到此错误 - output = cipher.doFinal(bFile); 有没有其他方法可以做到这一点?我该怎么办?

2 个答案:

答案 0 :(得分:1)

你有一个OOME因为bFile是一个数组,所以你可能在内存中有整个输入文件。 output是另一个字节数组,因此您还将整个输出文件保存在RAM中。如您所知,Android应用程序的Java堆具有最大大小(取决于设备,但常见的最小值为16MB)。

这是“阵列方法”的主要缺点之一。另一个是与数组缓冲区大小相关的填充问题。不幸的是,搜索引擎返回的大多数代码示例都显示了数组方法,因此在SO中存在大量关于相同问题的问题。

您应该知道有一种替代流方法。结果证明它更容易,更安全。它涉及使用CipherInputStream(用于解密)和CipherOutputStream进行加密。例如:

    InputStream is = new FileInputStream(...); //Input stream

    SecretKeySpec skey = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skey); 
    FileOutputStream fileOuputStream = new FileOutputStream(SD_CARD_PATH+ "/" + "abcd.db"); 
    CipherOutputStream cos = new CipherOutputStream(fileOuputStream, cipher);

    //Now read from input and write to output using your favorite utilities library
    //Guava and Apache Commons IO are good examples.
    FooUtils.copy(is, cos);
    //Remember to close streams if the previous call didn't (preferably in a finally block)

答案 1 :(得分:0)

您正在加密内存中的整个文件,然后编写它。 你应该做的是在多部分操作中一点一点地写它。

我认为你应该看看:Java 256-bit AES Password-Based Encryption

看看第二个答案。方法

public void WriteEncryptedFile (File input, File output)

应该完全按照您的需要做。 希望这会有所帮助。