使用零拷贝对文件高效的切片和合并

    技术2022-07-11  117

    使用零拷贝对文件高效的切片和合并

    对文件的切片/合并在应用中是一个很常见的需求,使用 FileChannel的 transferTo / transferFrom 的零拷贝方法(需要操作系统支持),可以高效的完成。

    切片

    /** * 对文件按照指定大小进行分片,在文件所在目录生成分片后的文件块儿 * @param file * @param chunkSize * @throws IOException */ public static void chunkFile(Path file, long chunkSize) throws IOException { if (Files.notExists(file) || Files.isDirectory(file)) { throw new IllegalArgumentException("文件不存在:" + file); } if (chunkSize < 1) { throw new IllegalArgumentException("分片大小不能小于1个字节:" + chunkSize); } // 原始文件大小 final long fileSize = Files.size(file); // 分片数量 final long numberOfChunk = fileSize % chunkSize == 0 ? fileSize / chunkSize : (fileSize / chunkSize) + 1; // 原始文件名称 final String fileName = file.getFileName().toString(); // 读取原始文件 try(FileChannel fileChannel = FileChannel.open(file, EnumSet.of(StandardOpenOption.READ))){ for (int i = 0; i < numberOfChunk; i++) { long start = i * chunkSize; long end = start + chunkSize; if (end > fileSize) { end = fileSize; } // 分片文件名称 Path chunkFile = Paths.get(fileName + "-" + (i + 1)); try (FileChannel chunkFileChannel = FileChannel.open(file.resolveSibling(chunkFile), EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))){ // 返回写入的数据长度 fileChannel.transferTo(start, end - start, chunkFileChannel); } } } }

    组合

    /** * 把多个文件合并为一个文件 * @param file 目标文件 * @param chunkFiles 分片文件 * @throws IOException */ public static void mergeFile (Path file, Path ... chunkFiles) throws IOException { if (chunkFiles == null || chunkFiles.length == 0) { throw new IllegalArgumentException("分片文件不能为空"); } try (FileChannel fileChannel = FileChannel.open(file, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))){ for (Path chunkFile : chunkFiles) { try(FileChannel chunkChannel = FileChannel.open(chunkFile, EnumSet.of(StandardOpenOption.READ))){ chunkChannel.transferTo(0, chunkChannel.size(), fileChannel); } } } }

    最后

    零拷贝

    https://zh.wikipedia.org/zh-hans/零复制

    Processed: 0.010, SQL: 9