Java 高效地散列目录中的所有文件(1000 2MB文件)

Java 高效地散列目录中的所有文件(1000 2MB文件),java,memory,hash,memory-leaks,md5,Java,Memory,Hash,Memory Leaks,Md5,我想散列(MD5)一个给定目录的所有文件,其中包含1000个2MB照片。 我试着只运行for循环,一次散列一个文件,但这会导致内存问题 我需要一种方法来高效地散列每个文件(内存方面) 我已经发布了3个关于我的问题的问题,但是现在我不想修改我的代码,我想看看什么是满足我需求的最佳通用方法 非常感谢你的帮助 public class MD5 { public static void main(String[] args) throws IOException { File file = n

我想散列(MD5)一个给定目录的所有文件,其中包含1000个2MB照片。 我试着只运行for循环,一次散列一个文件,但这会导致内存问题

我需要一种方法来高效地散列每个文件(内存方面)

我已经发布了3个关于我的问题的问题,但是现在我不想修改我的代码,我想看看什么是满足我需求的最佳通用方法

非常感谢你的帮助

public class MD5 {

public static void main(String[] args) throws IOException {
    File file = new File("/Users/itaihay/Desktop/test");
    for (File f : file.listFiles()) {
        try {
            model.MD5.hash(f);
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }
    }

private static MessageDigest md;
private static BufferedInputStream fis;
private static byte[] dataBytes;
private static byte[] mdbytes;

private static void clean() throws NoSuchAlgorithmException {
    md = MessageDigest.getInstance("MD5");
    dataBytes = new byte[8192];
}
public static void hash(File file) {
    try {
        clean();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    try {
        fis = new BufferedInputStream(new FileInputStream(file));
        int nread = 0;
        while ((nread = fis.read(dataBytes)) != -1) {
            md.update(dataBytes, 0, nread);
        }
        nread = 0;
        mdbytes = md.digest();  System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(mdbytes).toLowerCase());

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            fis.close();
            dataBytes = null;
            md = null;
            mdbytes = null;
        } catch (IOException e) {
            e.printStackTrace();
      }       
    }
  }
}

增加Java堆空间可以在短期内解决这个问题


长期来看,您希望将图像读取到一个可以放入内存的固定大小队列中。不要一下子把它们全部读进去。将最近的图像排队,将最早的图像排队。

MD5以64字节的块更新其状态,因此一次只需要内存中16字节的文件。MD5状态本身是128位,输出大小也是如此

最节省内存的方法是一次从每个文件中逐个文件读取64字节,并使用它来更新该文件的MD5状态。您最多需要999*16+64=16048~=16k内存


但是这样小的读取将是非常低效的,因此您可以从中增加文件的读取大小以适应内存限制。

正如其他人所说,使用内置Java MD5代码,您应该能够保持非常小的内存占用。我在散列大量Jar文件(每个文件高达几MB,通常一次500 MB)时也会做类似的事情,以获得良好的性能。在找到适合系统配置的最佳缓冲区大小之前,您肯定希望使用不同的缓冲区大小。以下代码段一次使用的字节数不超过
bufSize+128
,加上用于计算md5哈希的
文件
消息摘要
输入流
对象的可忽略开销:

InputStream is = null;
File f = ...
int bufSize = ...
byte[] md5sum = null;

try {
    MessageDigest digest = MessageDigest.getInstance("MD5");
    is = new FileInputStream(f);
    byte[] buffer = new byte[bufSize];

    int read = 0;
    while((read = is.read(buffer)) > 0) digest.update(buffer,0,read);
    md5sum = digest.digest();
} catch (Exception e){
} finally {
    try{
        if(is != null) is.close();
    } catch (IOException e){}
}

我们能看看你的密码吗?“如果我们不知道你的代码在做什么,我们就无法告诉你如何优化它。”路易斯瓦瑟曼添加了代码。