Java调用SevenZip.openArchive后无法删除文件的问题求助
问题:Spring Boot中使用SevenZip解压后无法删除本地文件
问题现象
接收Base64格式的RAR文件内容,使用SevenZip库解压过程正常,但执行归档打开代码后无法删除本地文件,抛出异常:
java.nio.file.FileSystemException: myFile.RAR: The process cannot access the file because it is being used by another process
已尝试Files.delete()和File.delete()两种删除方式均无效,且未找到SevenZip直接通过字节数组或InputStream打开归档的方法。优先使用SevenZip而非junrar(支持RAR5,损坏文件误判更少),希望实现解压后删除临时文件或无需保存本地直接解压,操作系统为Windows 10。
依赖配置(pom.xml)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>demo</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</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> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
DTO类
public record UploadDto( @NotNull String name, @NotNull String data) { }
控制器代码
import net.sf.sevenzipjbinding.IInArchive; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; @RestController public class TestController { private final Logger log = LoggerFactory.getLogger(TestController.class); @PostMapping("/upload") public void extractRar(@RequestBody UploadDto dto){ byte[] decodedBytes = Base64.getDecoder().decode(dto.data()); try { String filePath = dto.name(); Files.write(Paths.get(filePath), decodedBytes); log.info("File saved successfully to: " + filePath); File file = new File(filePath); IInArchive archive; try { archive = SevenZip.openInArchive(null, new RandomAccessFileInStream( new RandomAccessFile(file, "r"))); log.info(String.valueOf(archive.getNumberOfItems())); } catch (SevenZipException | FileNotFoundException e) { throw new RuntimeException(e); } archive.close(); // 1 method Files.delete(Path.of(filePath)); // 2 method if (file.delete()) { log.info("file deleted successfully"); } else { log.error("failed to delete the temporary file used for unzipping"); } } catch (IOException e) { throw new RuntimeException(e); } } }
请求体示例
{ "name": "myFile.RAR", "data": "UmFyIRoHAM+QcwAADQAAAAAAAABTL3QgkC8AFAAAABQAAAACTeXQiWmKL1cdMAoAIAAAAG15RmlsZS50eHQAsAA/PXJhciBkYXRhIG1vY2sgaGVyZQ0KxD17AEAHAA==" }
解决方案
原因分析
问题出在RandomAccessFile资源未被正确关闭——虽然调用了archive.close(),但RandomAccessFileInStream包装的底层RandomAccessFile对象没有被显式关闭,导致Windows系统中文件句柄被占用,无法删除文件。
解决方法1:显式关闭RandomAccessFile
将RandomAccessFile单独实例化,在finally块中显式关闭所有资源:
@PostMapping("/upload") public void extractRar(@RequestBody UploadDto dto){ byte[] decodedBytes = Base64.getDecoder().decode(dto.data()); try { String filePath = dto.name(); Files.write(Paths.get(filePath), decodedBytes); log.info("File saved successfully to: " + filePath); File file = new File(filePath); IInArchive archive = null; RandomAccessFile raf = null; try { raf = new RandomAccessFile(file, "r"); archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(raf)); log.info(String.valueOf(archive.getNumberOfItems())); // 添加解压逻辑 } catch (SevenZipException | FileNotFoundException e) { throw new RuntimeException(e); } finally { // 先关闭归档,再关闭底层RandomAccessFile if (archive != null) { try { archive.close(); } catch (SevenZipException e) { log.error("Failed to close archive", e); } } if (raf != null) { try { raf.close(); } catch (IOException e) { log.error("Failed to close RandomAccessFile", e); } } } // 删除文件 if (Files.deleteIfExists(Path.of(filePath))) { log.info("file deleted successfully"); } else { log.error("failed to delete the temporary file used for unzipping"); } } catch (IOException e) { throw new RuntimeException(e); } }
解决方法2:无需保存本地文件,直接用字节数组解压
使用SevenZipJBinding提供的ByteArrayInStream直接读取Base64解码后的字节数组,跳过本地文件存储步骤:
import net.sf.sevenzipjbinding.impl.ByteArrayInStream; @PostMapping("/upload") public void extractRar(@RequestBody UploadDto dto){ byte[] decodedBytes = Base64.getDecoder().decode(dto.data()); IInArchive archive = null; try { // 直接用字节数组打开归档,无需本地文件 archive = SevenZip.openInArchive(null, new ByteArrayInStream(decodedBytes)); log.info(String.valueOf(archive.getNumberOfItems())); // 遍历归档项并提取内容的示例逻辑 for (int i = 0; i < archive.getNumberOfItems(); i++) { if (!archive.isFolder(i)) { // 提取文件内容到输入流 archive.extractSlow(i, data -> { // 处理文件字节数据,比如写入输出流或数据库 return data.length; }); } } } catch (SevenZipException e) { throw new RuntimeException(e); } finally { if (archive != null) { try { archive.close(); } catch (SevenZipException e) { log.error("Failed to close archive", e); } } } }
关键说明
ByteArrayInStream是SevenZipJBinding专门处理字节数组的输入流实现,完美适配openInArchive方法,彻底避免本地文件的创建与删除问题。- 所有资源必须在
finally块中显式关闭,防止Windows系统中出现文件句柄泄漏。
内容的提问来源于stack exchange,提问作者S H
相关产品推荐
相关产品推荐

