我正在尝试使用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);
有没有其他方法可以做到这一点?我该怎么办?
答案 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)
应该完全按照您的需要做。 希望这会有所帮助。