java - 如何计算Inputstream的MD5

 先森还爱么z 发布于 2022-10-27 18:55

问题如下:

我首先通过文件上传取得了一个inputstream,这时如果我直接对这个流进行MD5的话,之后便无法保存文件了,应该是流已经被读取过无法再次读取。

MD5计算用的是apache commons-codec:
String md5 = DigestUtils.md5Hex(inputStream); // 之后无法保存文件
FileUtils.copyInputStreamToFile(inputStream, file); // 无法保存文件

请问有什么办法既能够得到MD5又能够保存文件呢,在只用inputstream的情况下,不要把流读入一个byte数组,我并不知道它多大。

4 个回答
  • 进行md5计算过后的inputStream他的指针已经指到末尾了
    所以在进行保存时就没有数据可以保存了

    使用inputStream的mark和reset可以将指针指到末尾后再回到mark的位置 但需要先将inputStream包装成BufferedInputStream类型

    2022-10-28 16:24 回答
  • 有人在SO上问了这个问题:
    http://stackoverflow.com/ques...

    思路就是用ByteArrayOutputStream先把inputstream的内容放到byte[]数组里,读的时候用ByteArrayInputStream读取。

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buf = new byte[1024];
    int n = 0;
    while ((n = myInputStream.read(buf)) >= 0)
        baos.write(buf, 0, n);
    byte[] content = baos.toByteArray();
    
    InputStream is1 = new ByteArrayInputStream(content);
    ... use is1 ...
    
    InputStream is2 = new ByteArrayInputStream(content);
    ... use is2 ...
    
    2022-10-28 16:25 回答
  • inputstream只能读取一次吧,你先把文件保存下来,在打开这个文件的流获取md5吧。

    2022-10-29 01:43 回答
  • 首先,最简单的方式就是把你的两行代码结合起来,先保存文件,再读取文件流计算MD5:

    public static String copyInputStreamToFileAndGetMd5Hex(InputStream inputStream, File file) throws IOException {
        FileUtils.copyInputStreamToFile(inputStream, file);
        return DigestUtils.md5Hex(new FileInputStream(file));
    }

    当然这样做要对同一个流读取两次,显得不够低碳环保。

    此时可以看下DigestUtils源码,追其根溯其源可以看到:

        public static MessageDigest updateDigest(final MessageDigest digest, final InputStream data) throws IOException {
            final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
            int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
    
            while (read > -1) {
                digest.update(buffer, 0, read);
                read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
            }
    
            return digest;
        }

    也不是多高级的技术,就是把整个InputStream拆成长度1024的字节数组逐个MD5。

    再看看FileUtils.copyInputStreamToFile源码的追根溯源实现:

        public static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException {
            long count;
            int n;
            for(count = 0L; -1 != (n = input.read(buffer)); count += (long)n) {
                output.write(buffer, 0, n);
            }
    
            return count;
        }

    同样也是讲InputStream拆成4096的字节数组,逐个写到目标文件中。

    那么,两者结合起来代码也就好写了:

        public static String copyInputStreamToFileAndGetMd5Hex(InputStream inputStream, File file) throws IOException {
    
            MessageDigest digest = DigestUtils.getMd5Digest();
    
            FileOutputStream outputStream = null;
    
            try {
                outputStream = new FileOutputStream(file);
                byte[] buffer = new byte[2048];
                int read = inputStream.read(buffer);
                while (read > -1) {
                    // 计算MD5,顺便写到文件
                    digest.update(buffer, 0, read);
                    outputStream.write(buffer, 0, read);
    
                    read = inputStream.read(buffer);
                }
            } finally {
                IOUtils.closeQuietly(outputStream);
            }
    
            return Hex.encodeHexString(digest.digest());
        }
    2022-10-29 01:47 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有