gpt4 book ai didi

加密期间 Java 内存不足错误

转载 作者:行者123 更新时间:2023-12-02 02:16:32 26 4
gpt4 key购买 nike

我正在使用 AES 来加密文件。当我尝试加密一个大文件时,问题首先出现了。所以我在网上做了一些阅读,发现我需要使用缓冲区并且一次只加密数据字节。

我将明文分成 8192 字节的数据 block ,然后对每个 block 应用加密操作,但仍然出现内存不足错误。

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()接受一个文件作为输入并返回一个字节数组

divideArray()将字节数组作为输入并将其划分为由较小字节数组组成的数组列表。

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)

如果我使用较小的文件,我不会收到此错误,但话又说回来,使用缓冲区的唯一目的是消除内存不足问题。

提前致谢。如有任何帮助,我们将不胜感激。

最佳答案

一个问题是在内存中保存数组和数组的副本。

分块读写。

然后doFinal不应重复。使用update反而。许多示例仅使用单个 doFinal这是误导性的。

所以:

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();
}
<小时/>

说明

一些字节 block 的加密如下:

  • 密码.init
  • Cipher.更新 block [0]
  • Cipher.update block [1]
  • Cipher.update block [2]
  • ...
  • Cipher.doFinal( block [n-1])

或者代替最后一个 doFinal:

  • Cipher.update( block [n-1])
  • Cipher.doFinal()

每个updatedoFinal产生一部分加密数据。

doFinal还“刷新”最终加密数据。

如果只有一个字节 block ,调用就足够了

byte[] encryptedBlock = cipher.doFinal(plainBlock);

然后就不会再调用 cipher.update需要。

对于其余部分,我使用了 try-with-resources 语法,它会自动关闭输入和输出流,即使 return 也是如此。发生,或者抛出异常。

而不是 File较新的Path更通用一点,与 Paths.get("...") 结合使用和非常好的实用程序类 Files可以提供强大的代码:如Files.readAllBytes(path)还有更多。

关于加密期间 Java 内存不足错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49235427/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com