一、前言
前段时间笔者在开发项目过程中涉及到大文件的传输功能。笔者实现的思路是先将大文件进行压缩,后分成多个小文件进行传输,接收端接收后再进行小文件合并,后再进行解压得到原文件。下面是笔者提供的工具类,可拿来直接使用。
二、工具类使用步骤
1.添加相关maven依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
2.工具类代码
package com.ctsi.dbbackup.core.util;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 文件分片、合并工具类
*
* @Author 屋顶上的蜗牛·
* @Date 2021-09-15
*/
@Slf4j
public class FileSplitUtil {
/**
* 1kb 可自行设定, 笔者在此为测试方便设为1kb
*/
private static final int FILE_SIZE = 1024;
/**
* 子文件下标
*/
private static final int FILE_NAME_EXT = 1000;
/**
* 文件结束标识
*/
private static final int EOF = -1;
/**
* 分片文件组成部分
*/
private static final String SPLIT_FILE_NAME = "-split.";
/**
* 匹配分片文件占位符
*/
private static final String PLACEHOLDER = "zzz";
/**
* 文件分片
*
* @param srcFile 待分片的源文件
* @param outPutDir 分片的输出目录
* @param compressType 压缩类型(文件后缀-可自行决定)
* @throws IOException 异常
*/
public static void split(File srcFile, String outPutDir, String compressType) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
//拆分成每个为10kb大小的文件
int saveSize = 10 * FILE_SIZE;
byte[] bytes = new byte[saveSize];
int length;
// 子文件下标
int filenameExt = FILE_NAME_EXT;
while ((length = bis.read(bytes)) > EOF) {
int ext = filenameExt++;
try (BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(outPutDir + ext + SPLIT_FILE_NAME + compressType))) {
bos.write(bytes, 0, length);
}
}
bis.close();
}
/**
* 合并分片文件 默认将合并后的文件放在其分片文件所在目录, 可行性决定
*
* @param sliceDir 所有分片文件所在目录
* @param compressType 压缩类型(文件后缀-可自行决定)
* @throws IOException 异常
*/
public static void merge(String sliceDir, String compressType) throws IOException {
List<String> subFileNames = getSplitFileNames(sliceDir, compressType);
if (subFileNames.size() < 1) {
throw new RuntimeException("目录下没有分片文件...");
}
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(sliceDir + UuidUtil.getUuid() + "." + compressType));
for (String subFilename : subFileNames) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sliceDir + subFilename))) {
// 每次读取1Mb大小的文件
byte[] bytes = new byte[FILE_SIZE];
int length;
while ((length = bis.read(bytes)) > EOF) {
bos.write(bytes, 0, length);
}
bos.flush();
} finally {
File eachSubFile = new File(sliceDir + subFilename);
if (eachSubFile.exists() && eachSubFile.delete()) {
log.info("删除分片文件成功...");
}
}
}
bos.close();
}
/**
* 获取目录下的所有分片文件名
*
* @param sliceDir 源目录
* @param compressType 压缩类型(文件后缀-可自行决定)
* @return 结果
*/
public static List<String> getSplitFileNames(String sliceDir, String compressType) {
File file = new File(sliceDir);
if (!file.isDirectory()) {
throw new RuntimeException("不是一个目录...");
}
String[] list = file.list();
if (list == null || list.length == 0) {
throw new RuntimeException("目录下没有任何文件...");
}
// 这里zzz为通用占位符、匹配分片文件
String filename = (PLACEHOLDER + SPLIT_FILE_NAME + compressType).replace(PLACEHOLDER, "\\d+");
return Arrays.stream(list)
.filter(s -> s.matches(filename))
.sorted()
.collect(Collectors.toList());
}
}
3.调用测试
- main方法
public static void main(String[] args) throws IOException {
// 分片
split(new File("E:/opt/aaa/test.zip"), "E:/opt/aaa/", "zip");
//合并
merge("E:/opt/bbb/", "zip");
}
-
调用前
-
调用后
三、结语
以上便是笔者封装的文件分片、合并工具类。若有出入的地方, 欢迎博友们指正。笔者感激不尽!