加密期间Java内存不足错误 [英] Java Out of Memory Error during Encryption
问题描述
我正在使用AES加密文件.当我尝试加密大文件时,问题首先出现.所以我做了一些在线阅读,发现我需要使用一个缓冲区,并且一次只加密数据字节.
I am using AES to encrypt files. The problem first came when i tried to encrypt a large file. So i did some reading online and figured that i need to use a buffer and only encrypt bytes of data at a time.
我将纯文本分为8192个字节的数据块,然后对每个这些块应用加密操作,但仍然遇到内存不足错误.
I divided my plaintext into chunks of 8192 bytes of data and then applied the encryption operation on each of these chunks but I am still getting the out of memory error.
public static File encrypt(File f, byte[] key) throws Exception
{
System.out.println("Starting Encryption");
byte[] plainText = fileToByte(f);
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
System.out.println(plainText.length);
List<byte[]> bufferedFile = divideArray(plainText, 8192);
System.out.println(bufferedFile.size());
List<byte[]> resultByteList = new ArrayList<>();
for(int i = 0; i < bufferedFile.size(); i++)
{
resultByteList.add(cipher.doFinal(bufferedFile.get(i)));
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for(byte[] b : resultByteList)
baos.write(b);
byte[] cipherText = baos.toByteArray();
File temp = byteToFile(cipherText, "D:\\temp");
return temp;
}
fileToByte()
将文件作为输入并返回字节数组
The fileToByte()
takes a file as input and returns a byte array
divideArray()
将字节数组作为输入,并将其划分为由较小字节数组组成的arraylist.
the divideArray()
takes a byte array as input and divides it into an arraylist consisting of smaller byte arrays.
public static List<byte[]> divideArray(byte[] source, int chunkSize) {
List<byte[]> result = new ArrayList<byte[]>();
int start = 0;
while (start < source.length) {
int end = Math.min(source.length, start + chunkSize);
result.add(Arrays.copyOfRange(source, start, end));
start += chunkSize;
}
return result;
}
这是我得到的错误
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3236)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
at java.io.OutputStream.write(OutputStream.java:75)
at MajorProjectTest.encrypt(MajorProjectTest.java:61)
at MajorProjectTest.main(MajorProjectTest.java:30)
如果我使用较小的文件,则不会出现此错误,但是再次,使用缓冲区的唯一目的是消除内存不足的问题.
I am not getting this error if I use a file of a smaller size, but then again, the sole purpose of using buffers was to eliminate the out of memory problem.
先谢谢了.感谢您的帮助.
Thanks in advance. Any help is appreciated.
推荐答案
一个问题是将数组和数组副本保存在内存中.
One problem is holding arrays and copies of arrays in memory.
读写块.
然后,不应重复 doFinal
.请改用 update
.许多示例仅使用单个 doFinal
就会产生误导.
Then doFinal
should not be repeated. Use update
instead. Many examples just use a single doFinal
which is misleading.
所以:
public static File encrypt(File f, byte[] key) throws Exception
{
System.out.println("Starting Encryption");
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
System.out.println(plainText.length);
Path outPath = Paths.get("D:/Temp");
byte[] plainBuf = new byte[8192];
try (InputStream in = Files.newInputStream(f.toPath());
OutputStream out = Files.newOutputStream(outPath)) {
int nread;
while ((nread = in.read(plainBuf)) > 0) {
byte[] enc = cipher.update(plainBuf, 0, nread);
out.write(enc);
}
byte[] enc = cipher.doFinal();
out.write(enc);
}
return outPath.toFile();
}
说明
Explanation
某些字节块的加密方式如下:
Encryption of some byte blocks goes as:
- Cipher.init
- Cipher.update块[0]
- Cipher.update块[1]
- Cipher.update块[2]
- ...
- Cipher.doFinal(block [n-1])
或者代替最后一个doFinal:
Or instead of the last doFinal:
- Cipher.update(block [n-1])
- Cipher.doFinal()
每次 update
或 doFinal
都会产生一部分加密数据.
Every update
or doFinal
yielding a portion of the encrypted data.
doFinal
还会刷新"最终的加密数据.
doFinal
also "flushes" final encryption data.
如果只有一个字节块,则足以调用
If one has only a single block of bytes, it suffices to call
byte[] encryptedBlock = cipher.doFinal(plainBlock);
然后不需要调用 cipher.update
.
对于其余的内容,我使用了try-with-resources语法,即使发生 return
或引发了异常,它也会自动关闭输入和输出流.
For the rest I used the try-with-resources syntax which automatically closes input and output streams, even should a return
happen, or an exception have been thrown.
更新的 Path
代替了 File
,具有更多用途,并且与 Paths.get("...")
结合使用非常好实用程序类 Files
可以提供强大的代码:例如 Files.readAllBytes(path)
等.
Instead of File
the newer Path
is a bit more versatile, and in combination with Paths.get("...")
and the very nice utility class Files
can provide powerful code: like Files.readAllBytes(path)
and much more.
这篇关于加密期间Java内存不足错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!