Java 将文件读入多字节数组
我有一个加密算法(AES),它接受转换为数组字节的文件并对其进行加密。 因为我要处理一个非常大的文件,JVM可能会内存不足。 我计划读取多字节数组中的文件,每个数组包含文件的某些部分。然后我迭代地输入算法。最后,我合并它们以生成一个加密文件 所以我的问题是:有没有办法将文件一部分一部分地读取到多字节数组中 我想我可以使用以下方法将文件读入字节数组:Java 将文件读入多字节数组,java,file,file-io,Java,File,File Io,我有一个加密算法(AES),它接受转换为数组字节的文件并对其进行加密。 因为我要处理一个非常大的文件,JVM可能会内存不足。 我计划读取多字节数组中的文件,每个数组包含文件的某些部分。然后我迭代地输入算法。最后,我合并它们以生成一个加密文件 所以我的问题是:有没有办法将文件一部分一部分地读取到多字节数组中 我想我可以使用以下方法将文件读入字节数组: IOUtils.toByteArray(InputStream input). 然后使用以下命令将阵列拆分为多个字节: Array
IOUtils.toByteArray(InputStream input).
然后使用以下命令将阵列拆分为多个字节:
Arrays.copyOfRange()
<>但是我担心读取文件到<代码> ByteArray < /C> >的代码会使JVM内存不足。
如果你使用<代码> IUTILLS ,也许你应该考虑
并指定a作为输出。然后,您可以使用offset/length遍历并加载文件的各个部分 从文档: 将大(超过2GB)输入流中的部分或所有字节复制到 OutputStream,可以选择跳过输入字节在Java中查找密码流。您可以使用它们动态加密/解密流,这样就不必将整个内容存储在内存中。您所要做的就是将源文件的常规
FileInputStream
复制到cipheroutstream
中,该文件将为加密的接收器文件包装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);
}
如果需要知道复制的字节数,如果文件大小超过Integer.MAX_值
字节(2 GB),则可以使用IOUtils.copyragle
而不是IOUtils.copy
要解密文件,请执行相同的操作,但使用CipherInputStream
而不是CipherOutputStream
,并使用Cipher.decrypt\u模式
初始化您的密码
查看有关Java中密码流的更多信息
这将为您节省空间,因为您不再需要存储自己的byte
数组。此系统中唯一存储的字节[]
是密码的内部字节[]
,每次输入足够的输入并且密码返回加密块时,该字节将被清除。更新,或关闭CipherOutputStream
时打开密码.doFinal
。然而,你不必担心这些,因为这些都是内部的,一切都是为你管理的
编辑:请注意,这可能会导致忽略某些加密异常,尤其是BadPaddingException
和IllegalBlockSizeException
。此行为可以在中找到。(当然,这个源代码来自OpenJDK,但它在Sun JDK中可能做了同样的事情。)另外,来自javadocs:
该类严格遵守其祖先类java.io.OutputStream
和java.io.FilterOutputStream
的语义,尤其是失败语义。该类正好具有在其祖先类中指定的那些方法,并重写它们此外,该类捕获其祖先类未引发的所有异常。
这里粗体的一行意味着加密异常将被忽略,而实际上它们是。这可能会在尝试读取加密文件时导致一些意外行为,尤其是对于块和/或填充加密算法(如AES)。记住这一点,加密(或解密为CipherInputStream
)文件将获得零或部分输出。大多数加密算法在数据块上工作,不需要一次完整的数据。这完全是为了避免您正在讨论的问题,您需要将整个明文存储在内存中,以便基于它计算密文。也许只需使用read(byte[],int,int)
函数一次读取一个块并将其提供给您的算法。在Java中查找密码流。您可以使用它们动态加密/解密流,这样就不必将整个内容存储在内存中。然后,您需要做的就是将源文件的常规FileInputStream
复制到CipherOutputStream
中,该文件将为加密的接收器文件包装FileOutputStream
IOUtils
甚至方便地包含一个copy(InputStream,OutputStream)
方法来为您执行此复制。如果您要复制到ByteArrayOutputStream中,这对内存使用有何帮助?因为您一次只复制部分。我本以为这是显而易见的,但我会修正的,我不明白为什么需要这样做。您可以改为使用缓冲流,尽管大部分时间磁盘I/O都是缓冲的,所以这并不重要。也许您不理解我的评论。为什么在将整个文件放入ByteArrayOutputStream(即“一个大字节数组”)时,一次复制部分文件很重要?(换句话说,您的ByteArrayOutputStream将导致内存问题)。@jtahlborn如果我没有弄错的话,他所提倡的是通过偏移量/长度将文件的一部分复制到BAS,从BAS获取字节,对它们进行加密,然后将加密的字节写入接收器输出流,然后用一个干净的包来完成整个过程。请记住,您可以重置BAO并限制其缓冲区大小。但此时,您也可以使用普通的byte[]
和输入流的int-read(byte[])
方法,完全跳过BAO。Java密码流可能会将异常推到表下,尤其是BadPaddingException
s。你已经被警告过了。嗯,会的。我会用这些信息更新我的答案。
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);
}