【无标题】 高效的获取文件的md5的方法

先直接上代码解决方案


import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class FileHashCalculator {

	private static final int CHUNK_SIZE = 1024 * 1024 * 10; // 10 MB

	public static String getMD5Checksum(String filePath) throws IOException, NoSuchAlgorithmException, InterruptedException, ExecutionException {
		File file = new File(filePath);
		if (!file.exists() || !file.isFile()) {
			throw new IllegalArgumentException("文件路径无效或文件不存在: " + filePath);
		}

		try (RandomAccessFile raf = new RandomAccessFile(file, "r");
		     FileChannel fileChannel = raf.getChannel()) {

			long fileSize = fileChannel.size();
			int numChunks = (int) Math.ceil((double) fileSize / CHUNK_SIZE);
			ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
			List<Future<byte[]>> futures = new ArrayList<>();

			for (int i = 0; i < numChunks; i++) {
				long offset = (long) i * CHUNK_SIZE;
				long chunkSize = Math.min(CHUNK_SIZE, fileSize - offset);
				futures.add(executor.submit(new MD5ChunkTask(fileChannel, offset, chunkSize)));
			}
			executor.shutdown();
			MessageDigest md = MessageDigest.getInstance("MD5");
			for (Future<byte[]> future : futures) {
				byte[] chunkMD5 = future.get();
				md.update(chunkMD5);
			}

			byte[] md5Bytes = md.digest();
			return convertBytesToHex(md5Bytes);
		}
	}

	private static String convertBytesToHex(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(String.format("%02x", b));
		}
		return sb.toString();
	}

	private static class MD5ChunkTask implements Callable<byte[]> {
		private final FileChannel fileChannel;
		private final long offset;
		private final long size;

		public MD5ChunkTask(FileChannel fileChannel, long offset, long size) {
			this.fileChannel = fileChannel;
			this.offset = offset;
			this.size = size;
		}

		@Override
		public byte[] call() throws Exception {
			MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, offset, size);
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(buffer);
			return md.digest();
		}
	}


	public static String getCompressFilePwd(String filePath) {
		String res = "";
		try {
			res = getMD5Checksum(filePath);
			if (StringUtils.isNotBlank(res)) {
				res = res.substring(0, 5);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return res;
	}

	public static void main(String[] args) {

		String filePath = "C:\\Users\\longf\\Downloads\\Compressed\\JH_Appform_V5.4_Linux_x64__DianKeXinYun_r40717.tar.gz";
		filePath = "C:\\Users\\longf\\Downloads\\Compressed\\test.txt";
		try {
			for (int i = 0; i < 10; i++) {
				StopWatch stopWatch = new StopWatch();
				stopWatch.start();
				String checksum = getCompressFilePwd(filePath);
				stopWatch.stop();
				System.out.println("CompressFilePwd: " + checksum);
				System.out.println("Time taken: " + stopWatch.getTime() + " ms");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

1. 文件操作和异常处理

文件操作
  • RandomAccessFile 和 FileChannel: 使用 RandomAccessFile 可以直接访问文件内容,并通过 FileChannel 进行高效的文件读取操作。在计算文件的 MD5 校验和时,利用 MappedByteBuffer 可以将文件的一部分映射到内存中,以加快数据处理速度。

  • MappedByteBuffer: 通过 FileChannel.map() 方法可以将文件的一部分映射到内存中的 MappedByteBuffer,从而避免频繁的 I/O 操作,提高文件数据的读取效率。

异常处理
  • IOException 和 NoSuchAlgorithmException: 在文件操作和安全算法(如 MD5 计算)中可能会抛出的异常需要进行适当的处理。在 getMD5Checksum 方法中使用了 throws IOException, NoSuchAlgorithmException 来声明可能抛出的异常,而在 getCompressFilePwd 方法中使用了捕获异常并抛出 RuntimeException 的方式处理异常。

2. 多线程计算

ExecutorService 和 Callable
  • ExecutorService: 使用 ExecutorService 可以管理和调度线程池中的线程,支持异步执行任务。在 getMD5Checksum 方法中,通过 Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) 创建一个固定大小的线程池,根据 CPU 核心数动态调整线程池大小,以最大化性能。

  • Callable 和 Future: 使用 Callable 接口定义可以返回结果的任务,并通过 Future 对象获取任务的执行结果。在 FileHashCalculator 中,MD5ChunkTask 类实现了 Callable<byte[]> 接口,在每个任务中计算文件的部分 MD5 值,并返回结果给主线程汇总计算。

3. 字符串处理和安全算法

MD5 校验和计算
  • MessageDigest: 使用 MessageDigest.getInstance("MD5") 获取 MD5 摘要算法的实例,通过 update(byte[]) 方法更新摘要内容,最后通过 digest() 方法计算出最终的 MD5 值。在 MD5ChunkTask 中,每个任务会计算文件的部分 MD5 值,并返回给主线程汇总计算。

  • 字符串处理: 使用 StringUtils.isNotBlank() 方法判断字符串是否不为空,避免空指针异常;使用 StringBuilder 类来拼接字符串,通过 String.format("%02x", b) 将字节数组转换为十六进制字符串表示 MD5 值。

4. 线程池技术

ExecutorService 和 Executors
  • ExecutorService: 是 Java 并发库提供的一个接口,用于管理线程的执行。ExecutorService 提供了一种灵活的线程管理机制,可以提交任务并控制线程池的行为。

  • Executors: 是 ExecutorService 的工厂类,提供了创建各种类型的线程池的静态方法。在 FileHashCalculator 类中,使用了 Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) 创建了一个固定大小的线程池,大小为当前运行环境的 CPU 核心数。这种做法可以最大程度地利用系统资源,提高多线程计算的效率。

5. 性能优化

分块计算和内存映射
  • CHUNK_SIZE: 在 FileHashCalculator 类中定义了一个 CHUNK_SIZE 常量,用于指定每次读取文件的块大小。通过将文件分成多个块进行计算,可以减少单次计算的数据量,降低内存使用,并且利用了操作系统的文件缓存机制,提高了文件读取的效率。

  • MappedByteBuffer: 使用 FileChannel.map() 方法创建 MappedByteBuffer,将文件的一部分映射到内存中。这种方式避免了传统的文件 I/O 操作中的数据复制,提升了文件读取和计算 MD5 值的效率。

6. 安全算法和异常处理

MD5 算法和异常处理
  • MessageDigest: 使用 MessageDigest.getInstance("MD5") 获取 MD5 摘要算法的实例,用于计算文件的 MD5 值。MD5 是一种常见的哈希算法,用于生成文件内容的唯一标识符。

  • 异常处理: 在 getMD5Checksum 方法中捕获并处理了 IOExceptionNoSuchAlgorithmException 异常,保证程序能够正确处理文件读取和算法调用可能抛出的异常情况。同时,在 getCompressFilePwd 方法中,将捕获的异常重新封装为 RuntimeException 抛出,使得异常处理更加灵活和简洁。

总结

FileHashCalculator 类通过利用多线程技术、文件分块读取、内存映射以及安全算法(MD5)来实现对文件 MD5 校验和的快速计算。这些技术点不仅提高了计算效率,还优化了内存使用和异常处理策略,使得类在处理大文件时表现出色,适用于需要高性能文件校验的场景。

https://doufei.eu.org/2024/07/18/java/%E9%AB%98%E6%95%88%E7%9A%84%E8%8E%B7%E5%8F%96%E6%96%87%E4%BB%B6%E7%9A%84md5/

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

智能网联汽车的安全员高级考试涉及多个方面的专业知识,包括但不限于自动驾驶技术原理、车辆传感器融合、网络安全防护以及法律法规等内容。以下是针对该主题的一些核心知识解析: ### 关于智能网联车安全员高级考试的核心内容 #### 1. 自动驾驶分级标准 国际自动机工程师学会(SAE International)定义了六个级别的自动驾驶等级,从L0到L5[^1]。其中,L3及以上级别需要安全员具备更高的应急处理能力。 #### 2. 车辆感知系统的组成与功能 智能网联车通常配备多种传感器,如激光雷达、毫米波雷达、摄像头和超声波传感器等。这些设备协同工作以实现环境感知、障碍物检测等功能[^2]。 #### 3. 数据通信与网络安全 智能网联车依赖V2X(Vehicle-to-Everything)技术进行数据交换,在此过程中需防范潜在的网络攻击风险,例如中间人攻击或恶意软件入侵[^3]。 #### 4. 法律法规要求 不同国家和地区对于无人驾驶测试及运营有着严格的规定,考生应熟悉当地交通法典中有关自动化驾驶部分的具体条款[^4]。 ```python # 示例代码:模拟简单决策逻辑 def decide_action(sensor_data): if sensor_data['obstacle'] and not sensor_data['emergency']: return 'slow_down' elif sensor_data['pedestrian_crossing']: return 'stop_and_yield' else: return 'continue_driving' example_input = {'obstacle': True, 'emergency': False, 'pedestrian_crossing': False} action = decide_action(example_input) print(f"Action to take: {action}") ``` 需要注意的是,“同学”作为特定平台上的学习资源名称,并不提供官方认证的标准答案集;建议通过正规渠道获取教材并参加培训课程来准备此类资格认证考试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值