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
>Solution :
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);
}
}