如何在不额外读流的情况下计算md5值
设想这样一个场景:从网络流中读取文件到硬盘中并计算文件的md5值。通常的做法是先将文件保存下来,再计算文件的md5,但这样会一共会出现三次I/O,一次网络I/O,两次磁盘I/O。
导致额外磁盘I/O的写法
import org.apache.commons.io.IOUtils; import org.springframework.util.DigestUtils; import java.io.*; import java.net.URL; public class Main { public static void main(String[] args) throws Exception { //下载文件,百度logo URL url = new URL("https://www.baidu.com/img/flexible/logo/plus_logo_web_2.png"); File file = new File("file.png"); try (InputStream in = url.openStream(); OutputStream out = new FileOutputStream(file)) { IOUtils.copy(in, out); } //计算md5 try (FileInputStream fileInputStream = new FileInputStream(file)) { //计算md5 String md5 = DigestUtils.md5DigestAsHex(fileInputStream); System.out.println(md5); } } }
上面的代码使用spring提供的MD5工具类,将流作为参数传入,直接返回md5值,这样的工具用起来简单方便,是很多人的首选。
然而,java提供的md5工具并没有这样的接口,java提供MessageDigest工具类计算md5时只提供了较为底层的接口,因为不好用,很多人忽视了它。
下面的例子中,下载文件并计算md5只用到一次磁盘I/O
import java.io.*; import java.math.BigInteger; import java.net.URL; import java.security.MessageDigest; public class Main { public static void main(String[] args) throws Exception { //下载文件,百度logo URL url = new URL("https://www.baidu.com/img/flexible/logo/plus_logo_web_2.png"); File file = new File("file.png"); //计算md5 MessageDigest md5Digest = MessageDigest.getInstance("md5"); try (InputStream in = url.openStream(); OutputStream out = new FileOutputStream(file)) { int len; byte[] buffer = new byte[1024 * 4]; while ((len = in.read(buffer)) != -1) { //更新散列值 md5Digest.update(buffer, 0, len); //写入文件 out.write(buffer, 0, len); } } //散列值数组 byte[] digest = md5Digest.digest(); //1表明这是无符号整数 BigInteger bigInteger = new BigInteger(1, digest); //以16进制的形式输出 System.out.println(bigInteger.toString(16)); } }
以上就是避免额外读流的方式计算md5,当然也可以推广到其他hash算法上,例如sha256等。
www.somanba.cn |
www.zuowenge.cn |
赞 (0)