设想这样一个场景:从网络流中读取文件到硬盘中并计算文件的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等。

如何在不额外读流的情况下计算md5值的更多相关文章

  1. 关于datagridview中checkbox列在选中行的情况下无法操作值

    这几天做项目的时候碰到了个小问题,在datagridview中实现对checkbox列的全选和反选功能.代码如下              //全选              if (dataGrid ...

  2. Java中只有按值传递,没有按引用传递!(两种参数情况下都是值传递)

    今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? 我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这 ...

  3. 知道一个数组某个index对应的值 不知道下标的情况下删除该值

    for (index,item) in Arr.enumerated() { if item == item { Arr.remove(at: index) } } 更好的方法是用数组的filter尾 ...

  4. 字符串、字节数组、流之间的相互转换以及文件MD5的计算

    using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace myMe ...

  5. 条目二十一《总是让比较函数在等值情况下返回false》

    条目二十一<总是让比较函数在等值情况下返回false> 这条目对序列容器是不适合的,因为序列容器就是通过等值判断来比较的. 对于关联容器来说,比较是等价比较,所以要注意等值的时候,比较子的 ...

  6. 手写node可读流之流动模式

    node的可读流基于事件 可读流之流动模式,这种流动模式会有一个"开关",每次当"开关"开启的时候,流动模式起作用,如果将这个"开关"设置成 ...

  7. 可读流 - nodejs stream总结

    可读流 包含的事件:data,readable,end,close ,error,pause,resume 常用方法:resume,read,pipe,pause 客户端的 HTTP 响应 服务器的 ...

  8. 极简 Node.js 入门 - 4.3 可读流

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  9. node中的可读流和可写流

    javascript的一个不足之处是不能处理二进制数据,于是node中引入了Buffer类型.这个类型以一个字节(即8位)为单位,给数据分配存储空间.它的使用类似于Array,但是与Array又有不同 ...

  10. JDK1.8 StampedLock: 解决ReentrantReadWriteLock在读多写少情况下,写线程饥饿问题

    ReentrantReadWriteLock 在沒有任何读写锁时,才可以取得写入锁,这可用于实现了悲观读取(Pessimistic Reading), 即如果执行中进行读取时,经常可能有另一执行要写入 ...

随机推荐

  1. ubuntu 18.04安装tensorflow (CPU)

    在已经安装anaconda环境及pip之后. 添加并设置pip配置文件: mkdir ~/.pip vim ~/.pip/pip.conf pip.conf文件内容: [global] index-u ...

  2. SpringBoot2.5.1+Mybatis-Plus3.4.3:(Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required)

    项目引发这个问题: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required <parent> <group ...

  3. linux学习相关资料整理

    linux常用指令记录 Python3.9.9安装 supervisor安装与监控nginx 使用supervisor监控mysql supervisor监控tomcat配置文件 nginx-1.22 ...

  4. 【Java SE】Day04 IDEA、方法*

    一.IDEA 1.快捷键 Ctrl+Alt+L/Ctrl+Alt+Shift+4:格式化代码 Alt+Insert:自动生成代码 修改快捷键:File->Settings->keymap- ...

  5. 【每日一题】【树的dfs递归,返回多次,注意都遍历完后才最终返回】2022年1月6日-112. 路径总和

    给你二叉树的根节点 root 和一个表示目标和的整数 targetSum .判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum .如果存在,返回 tr ...

  6. Spring学习笔记 - 第二章 - 注解开发、配置管理第三方Bean、注解管理第三方Bean、Spring 整合 MyBatis 和 Junit 案例

    Spring 学习笔记全系列传送门: Spring学习笔记 - 第一章 - IoC(控制反转).IoC容器.Bean的实例化与生命周期.DI(依赖注入) [本章]Spring学习笔记 - 第二章 - ...

  7. 网络监测工具之Zabbix的搭建与测试方法(二)-- SNMP、OID和MIB概述

    概念 SNMP是专门设计用于在 IP 网络管理网络节点的一种标准协议,它是一种应用层协议.SNMP使网络管理员能够管理网络效能,发现并解决网络问题以及规划网络增长.通过SNMP接收随机消息(及事件报告 ...

  8. [编程基础] C++多线程入门1-创建线程的三种不同方式

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 1 创建线程的三种不 ...

  9. 1_ES6中拓展运算符的使用

    一,拓展运算符(...) 拓展运算符(...):它会以参数序列的形式输出,更白话讲,比如数组,它可以把数组里面的东西一个一个的输出出来,例如 1 let arr1 =["你",&q ...

  10. Hive详解(05) - 压缩和存储

    Hive详解(05) - 压缩和存储 Hadoop压缩配置 MR支持的压缩编码 压缩格式 算法 文件扩展名 是否可切分 DEFLATE DEFLATE .deflate 否 Gzip DEFLATE ...