1. 依赖
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>java-unrar</artifactId>
<version>1.7.0-8</version>
</dependency>
<dependency>
<groupId>net.sf.sevenzipjbinding</groupId>
<artifactId>sevenzipjbinding</artifactId>
<version>16.02-2.01</version>
</dependency>
<dependency>
<groupId>net.sf.sevenzipjbinding</groupId>
<artifactId>sevenzipjbinding-all-platforms</artifactId>
<version>16.02-2.01</version>
</dependency>
2. 相关类
2.1 RarUtil
@Slf4j
public class RarUtil {
/**
* 解压rar文件
* @param rarFile
* @param dstDirectoryPath
* @return
*/
public static void unRar(File rarFile, String dstDirectoryPath){
if(dstDirectoryPath.startsWith("//")){
// 在Linux系统下,路径会已//开头需要替换为/
// 在windows系统下,路径会以会已磁盘符号开后,
log.info("==》Linux系统中,路径替换之前:{}", dstDirectoryPath);
dstDirectoryPath = dstDirectoryPath.replace("//","/");
}
log.info("最终解压目标目录路径:{}", dstDirectoryPath);
// 确保目标目录存在
File dstDir = new File(dstDirectoryPath);
if (!dstDir.exists()) {
if (!dstDir.mkdirs()) {
log.error("无法创建目标目录: {}", dstDirectoryPath);
return;
}
}
// 以只读模式 ("r") 打开一个RAR文件
try (RandomAccessFile randomAccessFile = new RandomAccessFile(rarFile, "r");
// 打开存档文件,null表示自动检测存档类型
// RandomAccessFileInStream将RandomAccessFile包装成输入流,以便SevenZip库可以读取
IInArchive archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile))) {
// 获取存档中的项目总数
int numberOfItems = archive.getNumberOfItems();
int[] indices = new int[numberOfItems];
for (int i = 0; i < numberOfItems; i++) {
indices[i] = i;
}
// 开始提取文件
// in: 指定要提取的文件索引数组;
// false: 表示不测试文件完整性,直接提取
// 提供一个回调接口实例来处理提取过程中的事件,dstDirectoryPath是目标目录路径。
archive.extract(indices, false, new RarExtractCallback(archive, dstDirectoryPath));
} catch (Exception e) {
log.error("解压文件时发生错误: {}", rarFile.getAbsolutePath(), e);
}
}
}
2.2 RarExtractCallback
@Slf4j
public class RarExtractCallback implements IArchiveExtractCallback {
private IInArchive inArchive;
private String ourDir;
private String lastPath = "";
public RarExtractCallback(IInArchive inArchive, String ourDir) {
this.inArchive = inArchive;
this.ourDir = ourDir;
}
@Override
public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
final String path = (String) inArchive.getProperty(index, PropID.PATH);
final boolean isFolder = (Boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
if (isFolder) {
File folder = new File(ourDir + File.separator + path);
if (!folder.exists() && !folder.mkdirs()) {
log.error("无法创建目录: {}", folder.getAbsolutePath());
return null;
}
return null;
}
File file = new File(ourDir + File.separator + path);
boolean append = path.equals(lastPath);
lastPath = path;
return data -> {
try {
saveFile(file, data, append);
} catch (Exception e) {
log.error("保存文件时发生错误: {}", file.getAbsolutePath(), e);
return 0;
}
return data.length;
};
}
@Override
public void prepareOperation(ExtractAskMode extractAskMode) throws SevenZipException {
}
@Override
public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
}
@Override
public void setTotal(long l) throws SevenZipException {
}
@Override
public void setCompleted(long l) throws SevenZipException {
}
public void saveFile(File file, byte[] msg, boolean append) {
File parent = file.getParentFile();
if (!parent.exists() && !parent.mkdirs()) {
log.error("创建目录异常: {}", parent.getAbsolutePath());
return ;
}
try (FileOutputStream fos = new FileOutputStream(file, append)) {
fos.write(msg);
fos.flush();
log.info("解压文件已成功保存: {}", file.getAbsolutePath());
} catch (IOException e) {
log.error("保存文件时发生错误: {}", file.getAbsolutePath(), e);
}
}
}
2.3 ExcelDataBO
@Data
public class ExcelDataBO {
@ExcelProperty("名字")
private String string;
@ExcelProperty("日期")
private Date date;
@ExcelProperty("工资")
private Double doubleData;
}
2.4 RarController
@Slf4j
@Api(tags = "Rar解压")
@RestController
@RequiredArgsConstructor
@RequestMapping("/rar")
public class RarController {
@PostMapping("/unRar")
@ApiOperation("Rar解压功能")
public String unRar(@RequestParam("file") MultipartFile file) throws Exception {
String filename = file.getOriginalFilename();
if (StrUtil.isBlank(filename) || !filename.toLowerCase().endsWith(".rar")) {
throw new Exception("【" + filename + "】文件不是rar格式!");
}
String currentDirectory = System.getProperty("user.dir") + File.separator + System.currentTimeMillis();
FileUtil.mkdir(currentDirectory);
String rarFilePath = currentDirectory + File.separator + "data.rar";
try {
// 下载文件到本地
File localFile = FileUtil.writeBytes(file.getBytes(), rarFilePath);
log.info("文件已保存到本地: {}", rarFilePath);
// 解压文件
RarUtil.unRar(localFile, currentDirectory);
// 通过文件夹地址获取里面的文件
File folder = new File(currentDirectory);
if (folder.exists() && folder.isDirectory()) {
File[] excelFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".xlsx") || name.toLowerCase().endsWith(".xls"));
if (excelFiles != null) {
for (File excelFile : excelFiles) {
log.info("保存【{}】Excel数据", excelFile);
saveExcelData(excelFile);
}
}
}
return "操作完成";
} catch (Exception e) {
log.error("文件上传或解压失败: {}", e.getMessage(), e);
FileUtil.del(currentDirectory);
throw new Exception("文件上传或解压失败!");
} finally {
log.info("删除临时文件夹: {}", currentDirectory);
FileUtil.del(currentDirectory);
}
}
/**
* 保存Excel数据
* @param excelFile
*/
private static void saveExcelData(File excelFile) {
EasyExcel.read(excelFile, ExcelDataBO.class, new ReadListener<ExcelDataBO>() {
/**
* 单次缓存的数据量
*/
public static final int BATCH_COUNT = 100;
/**
*临时存储
*/
private List<ExcelDataBO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
@Override
public void invoke(ExcelDataBO data, AnalysisContext context) {
log.info("解析数据:{}", data);
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("存储数据库成功【{}】条!", cachedDataList.size());
}
}).sheet().doRead();
}
}
3. 日志输入
3.1 window系统
输入日志: 文件已保存到本地: D:\RAR测试数据\1739805914204\data.rar 最终解压目标目录路径:D:\RAR测试数据\1739805914204 解压文件已成功保存: D:\RAR测试数据\1739805914204\测试数据01.xlsx 解压文件已成功保存: D:\RAR测试数据\1739805914204\测试数据02.xlsx 保存【D:\RAR测试数据\1739805914204\测试数据01.xlsx】Excel数据 解析数据:DemoData(string=张1, date=Mon Jan 01 00:00:00 CST 2024, doubleData=22222.2) 解析数据:DemoData(string=张2, date=Tue Jan 02 00:00:00 CST 2024, doubleData=22223.2) 解析数据:DemoData(string=张3, date=Wed Jan 03 00:00:00 CST 2024, doubleData=22224.2) 存储数据库成功【3】条! 保存【D:\RAR测试数据\1739805914204\测试数据02.xlsx】Excel数据 解析数据:DemoData(string=李1, date=Wed Jan 01 00:00:00 CST 2025, doubleData=888.88) 解析数据:DemoData(string=李2, date=Thu Jan 02 00:00:00 CST 2025, doubleData=889.88) 解析数据:DemoData(string=李3, date=Fri Jan 03 00:00:00 CST 2025, doubleData=890.88) 存储数据库成功【3】条! 删除临时文件夹: D:\RAR测试数据\1739805914204
3.2 linux系统
输入日志: 文件已保存到本地: //1739725342943/data.rar ==》Linux系统中,路径替换之前://1739725342943 最终解压目标目录路径:/1739725342943 解压文件已成功保存: /1739725342943/test01.xlsx 解压文件已成功保存: /1739725342943/test02.xlsx 保存【/1739725342943/test01.xlsx】Excel数据 解析数据:TestController.DemoData(string=张1, date=Mon Jan 01 00:00:00 CST 2024, doubleData=22222.2) 解析数据:TestController.DemoData(string=张2, date=Tue Jan 02 00:00:00 CST 2024, doubleData=22223.2) 解析数据:TestController.DemoData(string=张3, date=Wed Jan 03 00:00:00 CST 2024, doubleData=22224.2) 存储数据库成功【3】条! 保存【/1739725342943/test02.xlsx】Excel数据 解析数据:TestController.DemoData(string=李1, date=Wed Jan 01 00:00:00 CST 2025, doubleData=888.88) 解析数据:TestController.DemoData(string=李2, date=Thu Jan 02 00:00:00 CST 2025, doubleData=889.88) 解析数据:TestController.DemoData(string=李3, date=Fri Jan 03 00:00:00 CST 2025, doubleData=890.88) 存储数据库成功【3】条! 删除临时文件夹: //1739725342943