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

时间:2013-09-12 17:56:39

标签: java memory hash memory-leaks md5

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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

从长远来看,您希望将图像读入可以放入内存的固定大小的队列中。不要马上把它们全部读完。将最新图像排入队列并使最早的图像出列。

答案 2 :(得分:0)

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

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

但是这样的小读取效率非常低,所以从那里你可以增加文件的读取大小以适应你的内存限制。