我有一个加密算法(AES)接受转换为数组字节的文件并加密它.由于我要处理非常大的文件,JVM可能会耗尽内存.我计划读取多个字节数组中的文件,每个数组包含文件的某些部分.然后我迭代地提供算法.最后,我将它们合并以生成加密文件.
所以我的问题是:有没有办法将文件逐个读取到多个字节数组?
我以为我可以使用以下内容将文件读取为字节数组:
IOUtils.toByteArray(InputStream input).
Run Code Online (Sandbox Code Playgroud)
然后使用以下命令将数组拆分为多个字节:
Arrays.copyOfRange()
Run Code Online (Sandbox Code Playgroud)
但我担心读取文件的代码ByteArray会使JVM内存不足.
在Java中查找密码流.您可以使用它们来动态加密/解密流,这样您就不必将整个内容存储在内存中.您所要做的就是将FileInputStream源文件的常规文件复制到CipherOutputStream包装您FileOutputStream的加密接收器文件的常规文件中.IOUtils甚至方便地包含了copy(InputStream, OutputStream)为您执行此复制的方法.
例如:
public static void main(String[] args) {
encryptFile("exampleInput.txt", "exampleOutput.txt");
}
public static void encryptFile(String source, String sink) {
FileInputStream fis = null;
try {
fis = new FileInputStream(source);
CipherOutputStream cos = null;
try {
cos = new CipherOutputStream(new FileOutputStream(sink), getEncryptionCipher());
IOUtils.copy(fis, cos);
} finally {
if (cos != null)
cos.close();
}
} finally {
if (fis != null)
fis.close();
}
}
private static Cipher getEncryptionCipher() {
// Create AES cipher with whatever padding and other properties you want
Cipher cipher = ... ;
// Create AES secret key
Key key = ... ;
cipher.init(Cipher.ENCRYPT_MODE, key);
}
Run Code Online (Sandbox Code Playgroud)
如果您需要知道复制的字节数,则可以使用IOUtils.copyLarge而不是IOUtils.copy文件大小超过Integer.MAX_VALUE字节(2 GB).
要解密文件,请执行相同的操作,但请使用CipherInputStream 而不是CipherOutputStream初始化您的Cipher使用Cipher.DECRYPT_MODE.
有关Java中密码流的更多信息,请查看此处.
这将节省您的空间,因为您不再需要存储byte自己的数组.唯一的存储byte[]在本系统中是内部byte[]的Cipher,这将得到每个足够的输入被输入和一个加密的块被返回时间清零Cipher.update,或Cipher.doFinal当CipherOutputStream关闭.但是,您不必担心任何此问题,因为它都是内部的,所有内容都是为您管理的.
编辑:请注意,这可能会导致某些加密例外被忽略,特别是BadPaddingException和IllegalBlockSizeException.可以在CipherOutputStream源代码中找到此行为.(当然,这个源来自OpenJDK,但它可能在Sun JDK中做同样的事情.)另外,来自CipherOutputStream的 javadocs:
这个类严格遵守其祖先类
java.io.OutputStream和语义的语义,特别是失败语义java.io.FilterOutputStream.该类具有其祖先类中指定的那些方法,并将它们全部覆盖.此外,此类捕获其祖先类未抛出的所有异常.
这里的粗体线意味着忽略了加密异常,它们就是这样.这可能会在尝试读取加密文件时导致一些意外行为,尤其是对于块和/或填充加密算法(如AES).请记住这一点,您将获得加密(或解密CipherInputStream)文件的零或部分输出.