在 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);
}
如果您需要知道被复制的字节数,您可以使用IOUtils.copyLarge
而不是IOUtils.copy
文件大小超过Integer.MAX_VALUE
字节(2 GB)。
要解密文件,请执行相同的操作,但使用CipherInputStream
代替CipherOutputStream
并初始化您的Cipher
using 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
)文件的输出。