In my endpoint I receive the content of a file as String in format base64. Unzipping works fine with SevenZip library, no problems there. But after executing this line
archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(
new RandomAccessFile(file, "r")));
java is unable to delete file because of following exception:
java.nio.file.FileSystemException: myFile.RAR: The process cannot access the file because it is being used by another process
I have tried to use junrar library, but SevenZip works better (supports RAR5 and identifies less corupted files as junrar).
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>
Here is the dto:
public record UploadDto(
@NotNull
String name,
@NotNull
String data) {
}
Here is the controller with the logic:
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);
}
}
}
example of request body :
{
"name": "myFile.RAR",
"data": "UmFyIRoHAM+QcwAADQAAAAAAAABTL3QgkC8AFAAAABQAAAACTeXQiWmKL1cdMAoAIAAAAG15RmlsZS50eHQAsAA/PXJhciBkYXRhIG1vY2sgaGVyZQ0KxD17AEAHAA=="
}
I have tried 2 methods to delete the file, but none of them seems to work. Also I didn't find any method to openArchive using a byte array or InputStream. The problem would be solved if I could delete the file after extracting the content or to extract the content without saving the file locally. Any help or ideas would be appreciated! OS windows 10
Examples found online, close the file after closing the archive.
Something like the following (depending on your needs, you may want to try-catch the close() calls separately) :
@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;
RandomAccessFile randomAccessFile;
try {
randomAccessFile = new RandomAccessFile(file, "r");
archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
log.info(String.valueOf(archive.getNumberOfItems()));
} catch (SevenZipException | FileNotFoundException e) {
throw new RuntimeException(e);
}
archive.close();
randomAccessFile.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);
}
}