从URL获取文件的MD5哈希值

3

我得到的结果是,相同类型的文件返回相同的md5哈希值。例如,两个不同的jpg文件给出了相同的结果。但是,jpg与apk之间的结果不同。

这是我的代码...

public static String checkHashURL(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        InputStream is = new URL(input).openStream();

        try {
            is = new DigestInputStream(is, md);

            int b;

            while ((b = is.read()) > 0) {
                ;
            }
        } finally {
            is.close();
        }
        byte[] digest = md.digest();
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < digest.length; i++) {
            sb.append(
                    Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(
                            1));
        }
        return sb.toString();

    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

1
你确定要对jpg文件进行哈希处理,而不是针对404错误或DNS未找到错误进行处理吗? - Aki Suihkonen
1
我的猜测是只有文件数据的标题标签被读取和哈希,因此导致相似类型的文件看起来相等。我建议调试正在读取的数据。 - FThompson
1个回答

5

这个有问题:

while ((b = is.read()) > 0)

您的代码会在流中第一个字节为0时停止。如果在第一个0字节之前两个文件具有相同的值,则会失败。如果您真的想调用一次读取一个字节的版本read,您需要:

while (is.read() != -1) {}
没有参数的InputStream.read()方法在读到流的末尾时返回-1。

(不需要给b赋值,因为你没有使用它。)

更好的方式是一次读取一个缓冲区:

byte[] ignoredBuffer = new byte[8 * 1024]; // Up to 8K per read
while (is.read(ignoredBuffer) > 0) {}

这次的条件是有效的,因为如果传入一个空缓冲区,InputStream.read(byte[]) 将只会返回0。否则,它将尝试读取至少一个字节,返回读取的数据长度或-1(如果已到达流的结尾)。


2
@user1288686:不过这真的解决了问题吗? :) - Jon Skeet
是的,它有。还有一个问题...由于我正在逐字节读取文件,这会占用与下载文件相同的带宽吗?我在想这个问题,因为我正在开发这个应用程序来验证我的Android应用程序的下载更新,并受到运营商带宽限制的限制。 - k1komans
2
无论是逐字节读取还是一次读取缓冲区,您仍然会获取整个文件,所以是的。它确实正在下载文件,只是没有将其保存到磁盘上。 - Jon Skeet

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