我注意到当我在文件上使用readFully()
而不是read(byte[])时,处理时间大大减少了。然而,我突然意识到,readFully可能是一把双刃剑。如果我不小心试图读取一个巨大的,几gb的文件,它可能会卡住?
下面是我用来生成SHA-256校验和的函数:
public static byte[] createChecksum(File log, String type) throws Exception {
DataInputStream fis = new DataInputStream(new FileInputStream(log));
Long len = log.length();
byte[] buffer = new byte[len.intValue()];
fis.readFully(buffer); // TODO: readFully may come at the risk of
// choking on a huge file.
fis.close();
MessageDigest complete = MessageDigest.getInstance(type);
complete.update(buffer);
return complete.digest();
}
如果我用:
DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(log)));
这会减轻这种风险吗?还是……最好的选择是(在不能保证数据大小的情况下)始终控制读取的字节数并使用循环直到读取所有字节?
(考虑一下,由于MessageDigest API一次接受完整的字节数组,我不确定如何在不立即填充所有数据的情况下获得校验和,但我想这是另一个线程的另一个问题。
您应该分配一个适当大小的缓冲区(可能65536字节),并执行一次读取64kb的循环,使用"complete.update()"将内容添加到循环中的消化器中。在最后一个块上要小心,这样您只处理读取的字节数(可能小于64kb)
无论是否使用readFully(),读取文件所花费的时间都是相同的。
是否真的可以分配千兆字节大小的字节数组是另一个问题。下载文件时根本不需要使用readFully()。它在有线协议中使用,比如接下来的12个字节是一个标识符,后面跟着另外60个字节的地址信息,你不想要保持写循环。
readFully()如果文件是多个gb,则不会阻塞,但是分配字节缓冲区会阻塞。在调用readFully()之前,您将得到一个内存不足异常。
您需要使用使用文件块重复更新哈希的方法,而不是使用整个文件一次性更新它。