JAVA实现文件拆分与合并

文件拆分(切割)

将大文件拆分成多个小文件,每个小文件的大小可以自定义,这样可以方便传输,也可以方便存储。 步骤:

  1. 创建一个文件输入流对象,关联数据源文件

  2. 创建一个文件输出流对象,关联子文件

    • 为了防止子文件覆盖,需要在文件名后面加上编号

    • 会有多个子文件,所以需要使用循环

  3. 读取数据源文件,将读取到的字节写入到子文件

  4. 关闭资源

文件合并

将多个小文件合并成一个大文件,这样可以方便存储,也可以方便传输。 步骤:

  1. 创建一个文件输出流对象,关联目的地文件

  2. 创建一个文件输入流对象,关联数据源文件

    • 会有多个子文件,所以需要使用循环

  3. 读取数据源文件,将读取到的字节写入到目的地文件

  4. 关闭资源

代码 


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test01 {

    public static void main(String[] args) {
        File file = new File("d:/temp/jianghu.mp4"); //原文件
        long size = 1024 * 1024; //指定拆分后每个文件的大小
        File dir = new File("d:/temp/day01", "cutter"); //拆分后文件地址
        int count = split(file, size, dir); //计算拆分后文件数量
        System.out.println(count);
    }

    public static int split(final File original, final long size, final File directory) {
        // 参数校验
        if (original == null || !original.isFile()) {
            return 0;
        }

        // 输出文件夹是否存在
        if (!directory.exists()) {
            directory.mkdirs();
        }

        int count = 0; // 拆分文件的数量
        try (FileInputStream fis = new FileInputStream(original)) {
            // 单文件大小一个数组能读取到范围
            if (size <= Integer.MAX_VALUE - 8) {
                //最大数组大小定义为Integer.MAX_VALUE - 8,作为自己需要8 bytes存储大小
                byte[] bytes = new byte[(int) size];
                int readSize;   // readSize 读取的字节数
                while (fis.available() != 0) {//可读取字节数
                    readSize = fis.read(bytes);
                    File outFile = new File(directory, count++ + ".kfm");
                    // 用输出流创建子文件
                    FileOutputStream fos = new FileOutputStream(outFile);

                    fos.write(bytes, 0, readSize);//这么做防止写入重复的字节

                    System.out.println("分隔文件:" + outFile);
                    fos.close();
                }

            } else {
                // 一次读取不能完整读取一个文件  size > Integer.MAX_VALUE
                // 当前被分隔的文件是否以分隔完毕
                while (fis.available() != 0) { // 每循环一个会创建一个子文件
                    // 用输出流创建子文件
                    File outFile = new File(directory, count++ + ".part");
                    FileOutputStream fos = new FileOutputStream(outFile);

                    long sum = size; // 单文件大小

                    while (sum > Integer.MAX_VALUE - 8 && fis.available() != 0) {
                        byte[] bytes = new byte[Integer.MAX_VALUE - 8];
                        int readSize = fis.read(bytes);
                        fos.write(bytes, 0, readSize);
                        sum -= readSize;
                    }
                    // 没有满足单文件大小, 还有内容没读取
                    if (fis.available() != 0) {
                        byte[] bytes = new byte[(int) sum];
                        int readSize = fis.read(bytes);
                        fos.write(bytes, 0, readSize);
                    }
                    fos.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return count;
    }
}
package com.ketan.lianxi26;

import java.io.*;
import java.util.Arrays;

public class Test02 {

    public static void main(String[] args) {
        //拆分后文件地址
        File dir = new File("d:/temp/day01/cutter");
        //合并后文件存放地址
        File file = new File("d:/temp/合并后的视频.mp4");

        long size = join(dir, file);
        System.out.println(size);

//        String path = "d:/io/cutter/10.kfm";
//        String path1 = "d:/io/cutter/2.kfm";
//
//        System.out.println(path.compareTo(path1));
    }

    /**
     * 将指定目录中的多个文件片段依次序合并到同一个文件中,并返回合并后的文件体积
     *
     * @param dir    存放文件片段的目录(即拆分文件后的N个小文件的存放目录)
     * @param target 表示合并后的文件的存放路径
     * @return 返回合并后的文件体积
     * <p>
     * 合并后文件被损坏,原因:合并时子文件的顺序不对
     * 解决方案:
     * 1. 拆分时文件名按照顺序命名(单线程下可用时间戳做文件名)
     * 2. 根据文件名自定义排序规则
     */
    public static long join(final File dir, final File target) {
        long size = 0; // 声明用于统计合并后的文件体积的变量

        // 参数校验
        if (dir == null || !dir.isDirectory()) {
            return size;
        }

        // 参数校验
        if (target == null) {
            return size;
        }
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }

        // 合并文件
        File[] files = dir.listFiles((file, name) -> name.endsWith(".kfm"));

        if (files != null && files.length > 0) { // 判断是否有文件片段
            // 保证顺序
            Arrays.sort(files, (f1, f2) -> {
                String name1 = f1.getName();
                String name2 = f2.getName();

                int index1 = Integer.parseInt(name1.split("\\.")[0]);
                int index2 = Integer.parseInt(name2.split("\\.")[0]);

                return index1 - index2;
            });
            try {
                FileOutputStream fos = new FileOutputStream(target); // 创建文件输出流
                for (File file : files) { // 遍历文件片段
                    if (file.length() <= Integer.MAX_VALUE - 8) { // 一次可以完全读取
                        FileInputStream fileInputStream = new FileInputStream(file);
                        byte[] bytes = fileInputStream.readAllBytes();

                        fos.write(bytes);

                        fileInputStream.close();
                    } else {
                        // 一次不能完全读取
                        FileInputStream fileInputStream = new FileInputStream(file);

                        while (fileInputStream.available() != 0) {
                            byte[] bytes = new byte[Integer.MAX_VALUE - 8];
                            int readSize = fileInputStream.read(bytes);

                            fos.write(bytes, 0, readSize);
                        }

                        fileInputStream.close();
                    }
                    size += file.length();
                }
                fos.close();
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return size; // 返回合并后的文件体积
    }
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java可以通过IO流来实现文件拆分合并。 首先,对于大文件拆分,可以通过RandomAccessFile类来实现,该类提供了seek()和read()方法,可以指定读取文件的位置和读取的字节数。可以根据需求将大文件拆分成多个小文件,每个小文件的大小相同或者不同。 对于大文件合并,可以通过FileInputStream和FileOutputStream类来实现。可以将多个小文件按照指定的顺序读取并写入到一个大文件中。需要注意的是,在写入时需要使用追加模式,避免覆盖已有的文件内容。 下面是一个简单的例子,实现了将大文件拆分成多个小文件和将多个小文件合并成一个大文件的功能: ```java import java.io.*; public class FileUtil { //拆分文件 public static void splitFile(String filePath, int splitSize) throws IOException { File file = new File(filePath); if (!file.exists() || file.isDirectory()) { throw new IOException("文件不存在或者是一个目录"); } long fileSize = file.length(); int fileNum = (int) Math.ceil((double) fileSize / splitSize); byte[] buffer = new byte[1024]; int len; try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { for (int i = 0; i < fileNum; i++) { String fileName = file.getName() + "." + (i + 1); try (FileOutputStream fos = new FileOutputStream(fileName)) { int count = 0; while ((len = raf.read(buffer)) != -1) { fos.write(buffer, 0, len); count += len; if (count >= splitSize) { break; } } } } } } //合并文件 public static void mergeFile(String destPath, String... sourcePaths) throws IOException { File destFile = new File(destPath); if (destFile.exists()) { destFile.delete(); } try (FileOutputStream fos = new FileOutputStream(destFile, true)) { for (String sourcePath : sourcePaths) { File sourceFile = new File(sourcePath); if (!sourceFile.exists() || sourceFile.isDirectory()) { throw new IOException("文件不存在或者是一个目录"); } try (FileInputStream fis = new FileInputStream(sourceFile)) { byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } } } } } } ``` 使用方法: ```java //拆分文件 FileUtil.splitFile("test.txt", 1024 * 1024); //合并文件 FileUtil.mergeFile("test_merge.txt", "test.txt.1", "test.txt.2", "test.txt.3"); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值