计算输入流的校验和

时间:2014-07-21 13:41:32

标签: java md5 checksum

我需要为输入流(或文件)计算校验和,以检查文件内容是否已更改。我有以下代码,虽然我使用相同的流,但每次执行都会生成不同的值。有人可以帮我做这件事吗?

public class CreateChecksum {
    public static void main(String args[]) {
        String test = "Hello world";
        ByteArrayInputStream bis = new ByteArrayInputStream(test.getBytes());
        System.out.println("MD5 checksum for file using Java : "    + checkSum(bis));
        System.out.println("MD5 checksum for file using Java : "    + checkSum(bis));
    }
    public static String checkSum(InputStream fis){
        String checksum = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            //Using MessageDigest update() method to provide input
            byte[] buffer = new byte[8192];
            int numOfBytesRead;
            while( (numOfBytesRead = fis.read(buffer)) > 0){
                md.update(buffer, 0, numOfBytesRead);
            }
            byte[] hash = md.digest();
            checksum = new BigInteger(1, hash).toString(16); //don't use this, truncates leading zero
        } catch (Exception ex) {                  
        }
       return checksum;
    }
}

5 个答案:

答案 0 :(得分:5)

您正在为两个调用使用相同的流对象 - 在您调用checkSum一次后,该流将不再有任何数据要读取,因此第二个调用将正在创建一个空流的哈希。最简单的方法是每次创建一个新流:

String test = "Hello world";
byte[] bytes = test.getBytes(StandardCharsets.UTF_8);
System.out.println("MD5 checksum for file using Java : " 
    + checkSum(new ByteArrayInputStream(bytes)));
System.out.println("MD5 checksum for file using Java : " 
    + checkSum(new ByteArrayInputStream(bytes)));

请注意,checkSum 中的异常处理确实需要修复,以及十六进制转换......

答案 1 :(得分:0)

文件的更改相对容易监视,每次更改(和关闭)文件时,File.lastModified()都会更改。甚至还有一个内置API可以获得有关文件系统所选更改的通知:http://docs.oracle.com/javase/tutorial/essential/io/notification.html

InputStream的hashCode不适合检测更改(没有定义InputStream应如何计算其hashCode - 很可能是它使用Object.hashCode,这意味着hashCode不依赖于除了对象标识之外的任何东西)

像尝试一样构建MD5,但每次都需要读取整个文件。如果文件很大和/或正在观看多个文件,那么这是一个性能杀手。

答案 2 :(得分:0)

你混淆了两个相关但不同的责任。

首先你有Stream提供要阅读的东西。然后你在那个流上有一个校验和;但是,您的实现是一个static方法调用,实际上将它与一个类分开,这意味着没有人负责维护校验和。

尝试重新处理您的解决方案

public ChecksumInputStream implements InputStream {
  private InputStream in;

  public ChecksumInputStream(InputStream source) {
    this.in = source;
  }

  public int read() {
    int value = in.read();
    updateChecksum(value);
    return value;
  }

  // and repeat for all the other read methods.
}

请注意,现在您只进行一次读取,校验和计算器将装饰原始输入流。

答案 3 :(得分:0)

问题出在您第一次阅读输入流之后。该pos已经到了终点。解决问题的快捷方法是

ByteArrayInputStream bis = new ByteArrayInputStream(test.getBytes());         System.out.println("使用Java的文件的MD5校验和:" + checkSum(bis));

bis = new ByteArrayInputStream(test.getBytes());

    System.out.println("MD5 checksum for file using Java : "    + checkSum(bis));

答案 4 :(得分:-1)

查看org / apache / commons / codec / digest / DigestUtils.html中的代码