java - 如何计算Inputstream的MD5
黄舟
黄舟 2017-04-18 09:55:55
0
4
1067

问题如下:

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

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

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

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回覆(4)
黄舟

首先,最簡單的方式就是把你的兩行程式碼結合起來,先儲存文件,再讀取文件流計算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());
    }
大家讲道理

inputstream只能读取一次吧,你先把文件保存下来,在打开这个文件的流获取md5吧。

左手右手慢动作

有人在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 ...
迷茫

進行md5計算後的inputStream他的指標已經指到末尾了
所以在進行保存時就沒有資料可以保存了

使用inputStream的mark和reset可以將指標指向末尾後再回到mark的位置 但需要先將inputStream包裝成BufferedInputStream類型

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板