Java FileChannel文件切片、合并

背景

项目组自己搭建的文件服务器,要支持文件切片上传、断点续传能力

下面是个简单的demo

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileClient {

    // 文件分片
    public static void sliceFile() {

        File file = new File("D:\\Test_report.docx");
        long totalSize = file.length();
        System.out.println("文件总大小:" + totalSize);
        // 文件总大小:169808
        
        // 设置单个分片大小,为了便于调试,做成25kb一个切片
        long chunkSize = 25600;
        // 判断总分片数量
        long totalChunks = totalSize/chunkSize + (totalSize%chunkSize == 0 ? 0 : 1);
        for (int i = 1; i <= totalChunks; i ++) {
            File sliceFile = fileSlice(file, chunkSize, (int) totalChunks, i);
            System.out.println(sliceFile.getAbsolutePath() + "======" + sliceFile.length());
        }
        //D:\1.1-code\tools_service\Test_report.docx_1======25600
        //D:\1.1-code\tools_service\Test_report.docx_2======25600
        //D:\1.1-code\tools_service\Test_report.docx_3======25600
        //D:\1.1-code\tools_service\Test_report.docx_4======25600
        //D:\1.1-code\tools_service\Test_report.docx_5======25600
        //D:\1.1-code\tools_service\Test_report.docx_6======25600
        //D:\1.1-code\tools_service\Test_report.docx_7======16208
    }

    public static void main(String[] args) {
        //sliceFile();
        assembleFile();
    }

    // 文件合并
    public static void assembleFile() {

        try {
            // 设定合并后的文件
            File resultFile = new File("D:\\1.1-code\\tools_service\\Test_report.docx");
            RandomAccessFile raf = new RandomAccessFile(resultFile, "rw");
            FileChannel fileChannel = raf.getChannel();
            for (int i = 1; i <= 7; i ++) {
                long position = (i - 1) * 25600;
                File sliceFile = new File("D:\\1.1-code\\tools_service\\Test_report.docx_" + i);
                System.out.println(sliceFile.getAbsolutePath() + "======" + sliceFile.length());
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sliceFile));
                byte[] fileBytes = new byte[bis.available()];
                bis.read(fileBytes);
                bis.close();

                fileChannel.position(position);
                fileChannel.write(ByteBuffer.wrap(fileBytes));
                fileChannel.force(true);
            }
            fileChannel.close();
            raf.close();
            System.out.println("文件总大小:" + resultFile.length());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 文件切片
    public static File fileSlice(File file, long m, int totalCount, int index) {

        FileInputStream in;
        FileOutputStream out;
        FileChannel inChannel;
        FileChannel outChannel;
        // long m = 51200L;
        File templateFile = null;
        try {
            in = new FileInputStream(file);
            inChannel = in.getChannel();

            // 创建临时文件,并保持每个分片的文件名和原始文件名相同
            String t = file.getName() + "_" + index;
            templateFile = new File(t);
            out = new FileOutputStream(templateFile);
            outChannel = out.getChannel();
            // 从inChannel的m*i处,读取固定长度的数据,写入outChannel
            if (index != totalCount) {
                inChannel.transferTo(m * (index - 1), m, outChannel);
            } else {
                // 最后一个文件,大小不固定,所以需要重新计算长度
                inChannel.transferTo(m * (index-1), (file.length() - m * (index-1)), outChannel);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return templateFile;
    }
}

说两句

1、demo很简单,真正使用时,可以增加参数:文件总大小、本次切片大小,本次切片的序号等,用于判断当前是第几片文件,文件是否已完成上传,是否已完成合并;
2、尽量保持按顺序上传、合并文件;如果乱序应该会导致文件合并失败,但尚未测试,大家可以试试。

更新

网上有篇文章写了FileChannel的原理:https://www.jb51.net/article/283766.htm,有兴趣的可以看看

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值