java 模拟前端分片上传

    <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
import org.apache.commons.codec.digest.DigestUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class FileProcessor {


    /**
     * 演示使用
     */
    public static void main(String[] args) {
        String testFile = "E:/jt/save/寂寞的季节.mp4";

        try {
            // 每片大小10M
            long chunkSize = 10L * 1024 * 1024;

            // 1.计算原文件MD5(模拟前端)
            InputStream inputStream = Files.newInputStream(Paths.get(testFile));
            String originalMD5 = DigestUtils.md5Hex(inputStream);
            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 = Files.readAllBytes(Paths.get(chunks.get(i)));
                saveChunk(bytes, i, chunkSize, "E:\\jt\\save\\"+originalMD5+".mp4");
            }

        } 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;
        }
    }


    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();
        }
    }



}

 

posted @ 2025-02-21 13:59  真某人  阅读(25)  评论(0)    收藏  举报