我正在尝试使用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);
中遇到此错误还有其他方法吗?我该怎么办?
您有一个OOME,因为bFile
是一个数组,因此您可能在内存中拥有整个输入文件。output
是另一个字节数组,因此您还将整个输出文件持有RAM。如您所知
这是"数组方法"的主要缺点之一。另一个是与阵列缓冲区大小有关的填充问题。不幸的是,搜索引擎返回的大多数代码示例都显示了数组方法,因此,存在很多问题。
您应该知道有一种替代流方式。事实证明,它更容易更安全。它涉及使用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)
您在内存中加密整个文件,然后编写它。您应该做的是在多个部分操作中逐渐编写。
我认为您应该查看:Java 256位基于密码的加密
看第二个答案。方法
public void WriteEncryptedFile (File input, File output)
应该准确地做您需要做的事情。希望这会有所帮助。