import java.io.*; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List;public class FileProcessor {/*** 演示使用*/public static void main(String[] args) {String testFile = "E:\\jt\\save\\10.jpg";try {// 每片大小10Mlong chunkSize = 10L * 1024 * 1024;// 1.计算原文件MD5(模拟前端)String originalMD5 = calculateMD5(testFile);System.out.println("Original MD5: " + originalMD5);// 2.分片处理(10MB分片)(模拟前端)List<String> chunks = splitFile(testFile, chunkSize);System.out.println("Generated chunks: " + chunks.size());// 3.分片合并(模拟后端分片上传)for (int i = 0; i < chunks.size(); i++) {byte[] bytes = readByFileInputStream(chunks.get(i));saveChunk(bytes, i, chunkSize, "E:\\jt\\save\\"+originalMD5+".jpg");}} catch (Exception e) {e.printStackTrace();}}/*** 文件分片(自动处理剩余字节)* @param sourceFile 源文件路径* @param chunkSizeBytes 分片大小(b)* @return 分片文件路径列表*/public static List<String> splitFile(String sourceFile, long chunkSizeBytes) throws IOException {List<String> chunks = new ArrayList<>();try (RandomAccessFile raf = new RandomAccessFile(sourceFile, "r")) {long fileSize = raf.length();int chunkIndex = 0;long bytesProcessed = 0;while (bytesProcessed < fileSize) {long remaining = fileSize - bytesProcessed;int currentChunkSize = (int) Math.min(chunkSizeBytes, remaining);// 生成分片文件路径String chunkPath = sourceFile + ".part" + chunkIndex;try (RandomAccessFile chunkRaf = new RandomAccessFile(chunkPath, "rw")) {copyBytes(raf, chunkRaf, bytesProcessed, currentChunkSize);}chunks.add(chunkPath);bytesProcessed += currentChunkSize;chunkIndex++;}}return chunks;}/*** 安全字节拷贝(带边界检查)*/private static void copyBytes(RandomAccessFile src, RandomAccessFile dest, long startPos, int chunkSize) throws IOException {src.seek(startPos);byte[] buffer = new byte[4096];int totalRead = 0;while (totalRead < chunkSize) {int remaining = chunkSize - totalRead;int bytesToRead = Math.min(buffer.length, remaining);int bytesRead = src.read(buffer, 0, bytesToRead);if (bytesRead == -1) {break;}dest.write(buffer, 0, bytesRead);totalRead += bytesRead;}}/*** 安全的MD5计算(支持大文件)*/public static String calculateMD5(String filePath) throws Exception {try (InputStream is = new FileInputStream(filePath)) {MessageDigest md = MessageDigest.getInstance("MD5");byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {md.update(buffer, 0, bytesRead);}StringBuilder sb = new StringBuilder();for (byte b : md.digest()) {sb.append(String.format("%02x", b));}return sb.toString();}}public static void saveChunk(byte[] bytes, Integer index, Long chunkSize, String resultFileName) {try (RandomAccessFile randomAccessFile = new RandomAccessFile(resultFileName, "rw")) {// 偏移量long offset = chunkSize * index;// 定位到该分片的偏移量 randomAccessFile.seek(offset);// 写入 randomAccessFile.write(bytes);} catch (IOException e) {e.printStackTrace();}}public static byte[] readByFileInputStream(String filePath) throws IOException {try (FileInputStream fis = new FileInputStream(filePath);ByteArrayOutputStream bos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {bos.write(buffer, 0, bytesRead);}return bos.toByteArray();}}}