将文件读入内存的Java方法,如何避免内存溢出问题

5
我是Java的新手,正在尝试对文件执行MAC计算。由于文件大小在运行时未知,因此我无法将整个文件加载到内存中。所以我编写了代码来逐位读取(在这种情况下为4k)。但问题在于,我尝试将整个文件加载到内存中,以查看两种方法是否产生相同的哈希值。然而它们似乎产生了不同的哈希值。
以下是逐位代码:
FileInputStream fis = new FileInputStream("sbs.dat");
byte[] file = new byte[4096];
m = Mac.getInstance("HmacSHA1");
int i=fis.read(file);
m.init(key);
while (i != -1)
{
    m.update(file);
    i=fis.read(file);
}
mac = m.doFinal();

这里是一次性的方法:

File f = new File("sbs.dat");
long size = f.length();
byte[] file = new byte[(int) size];
fis.read(file);
m = Mac.getInstance("HmacSHA1");
m.init(key);
m.update(file);
mac = m.doFinal();

它们不应该生成相同的哈希值吗?

然而,这个问题更通用。第一段代码是将文件分块加载到内存中并在while循环内执行我们想要执行的任何操作(socket发送、加密文件等)的正确方式吗? 这个问题很有用,因为我看过的每个教程都是一次性加载所有内容...

更新:工作正常 :-D。通过socket分块发送文件这种方法是否能正常工作?

3个回答

5

不,你无法保证fis.read(file)会读取file.length个字节。这就是为什么read()返回一个int告诉你它实际读取了多少字节。

你应该这样做:

m.init(key);
int i=fis.read(file);

while (i != -1)
{
    m.update(file, 0, i);
    i=fis.read(file);
}

利用Mac.update(byte[] data, int offset, int len)方法,可以指定byte[]数组中实际数据的长度。

糟糕,我感觉自己像个白痴,我完全忘记了Mac类中有3种更新方法。尽管如此,我仍然会在某些简单的事情上浪费数小时。我会试一下,但听起来对了。 - ptguy

4
< p > read 函数不一定会填满整个数组。因此,您需要检查从read函数返回了多少字节,并仅使用缓冲区中那么多的字节。


1

就像Jason LeBrun所说的那样- read方法并不总是读取指定数量的字节。例如:如果文件不包含4096字节的倍数,你认为会发生什么?

我会选择类似这样的东西:

        FileInputStream fis = new FileInputStream(filename);
        byte[] buffer = new byte[buffersize];
        Mac m = Mac.getInstance("HmacSHA1");
        m.init(key);

        int n;
        while ((n = fis.read(buffer)) != -1)
        {
            m.update(buffer, 0, n);
        }
        byte[] mac = m.doFinal();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接