【问题标题】:Efficiently hashing all the files of a directory (1000 2MB files)有效地散列一个目录的所有文件(1000 个 2MB 文件)
【发布时间】:2013-09-12 17:56:39
【问题描述】:

我想散列 (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();
      }       
    }
  }
}

【问题讨论】:

  • 我们可以看看你的代码吗?如果我们不知道代码在做什么,我们就无法知道如何优化您的代码。
  • @LouisWasserman 添加了代码。

标签: java memory hash memory-leaks md5


【解决方案1】:

正如其他人所说,使用内置 Java MD5 代码,您应该能够保持非常小的内存占用。在散列大量 Jar 文件(每个文件最多几 MB,通常一次价值 500MB)并获得不错的性能时,我会做类似的事情。您肯定会想要使用不同的缓冲区大小,直到找到适合您的系统配置的最佳大小。以下代码-sn-p 一次使用不超过 bufSize+128 字节,加上用于计算 md5 哈希的 FileMessageDigestInputStream 对象的开销可忽略不计:

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){}
}

【讨论】:

    【解决方案2】:

    增加 Java 堆空间可以在短期内解决它。

    从长远来看,您希望考虑将图像读取到可以放入内存的固定大小的队列中。不要一次全部读完。将最近的图像加入队列,将最早的图像出队。

    【讨论】:

      【解决方案3】:

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

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

      但是如此小的读取效率会非常低,因此您可以从那里增加文件的读取大小以适应您的内存限制。

      【讨论】:

        猜你喜欢
        • 2013-10-14
        • 2012-09-02
        • 2013-12-31
        • 2018-05-02
        • 2013-11-13
        • 1970-01-01
        • 1970-01-01
        • 2013-03-24
        相关资源
        最近更新 更多