Added FileUtils / TempDirectory from EmailTool.

Moved FileUtils to io package.
This commit is contained in:
Konrad Neitzel
2025-07-01 15:38:07 +02:00
parent 2b60038774
commit 5aa75be6ba
9 changed files with 550 additions and 306 deletions
@@ -1,6 +1,6 @@
package de.neitzel.core.config;
import de.neitzel.core.util.FileUtils;
import de.neitzel.core.io.FileUtils;
import de.neitzel.core.util.Strings;
import lombok.extern.slf4j.Slf4j;
@@ -28,7 +28,7 @@ public class Configuration {
* A {@link Properties} object that stores a set of key-value pairs.
* This variable can be used to manage configuration settings or other
* collections of properties within the application.
*
* <p>
* It provides methods to load, retrieve, and modify properties
* as necessary for the application's requirements.
*/
@@ -56,20 +56,20 @@ public class Configuration {
* Retrieves a boolean property value associated with the specified key. If the key does not exist in the properties,
* the provided default value is returned. The method also supports interpreting specific string values as true.
*
* @param key the key used to retrieve the boolean property
* @param key the key used to retrieve the boolean property
* @param defaultValue the default value returned if the key is not found in the properties
* @return the boolean value associated with the key, or the defaultValue if the key does not exist
*/
protected boolean getBooleanProperty(final String key, final boolean defaultValue) {
if (!properties.containsKey(key)) return defaultValue;
return getStringProperty(key, defaultValue ? "ja": "nein").equalsIgnoreCase("ja") || properties.getProperty(key).equalsIgnoreCase("true");
return getStringProperty(key, defaultValue ? "ja" : "nein").equalsIgnoreCase("ja") || properties.getProperty(key).equalsIgnoreCase("true");
}
/**
* Retrieves the value of the specified property as a trimmed string.
* If the property is not found, the default value is returned.
*
* @param key the key of the property to retrieve
* @param key the key of the property to retrieve
* @param defaultValue the default value to return if the property is not found
* @return the trimmed string value of the property, or the default value if the property is not found
*/
@@ -82,34 +82,22 @@ public class Configuration {
* Retrieves a string property value associated with the specified key, applies
* environment variable expansion on the value, and returns the processed result.
*
* @param key the key identifying the property to retrieve.
* @param key the key identifying the property to retrieve.
* @param defaultValue the default value to use if the property is not found.
* @return the processed property value with expanded environment variables, or
* the defaultValue if the property is not found.
* the defaultValue if the property is not found.
*/
protected String getStringPropertyWithEnv(final String key, final String defaultValue) {
String result = getStringProperty(key, defaultValue);
return Strings.expandEnvironmentVariables(result);
}
/**
* Retrieves the value of a string property associated with the specified key,
* removes any surrounding quotes from the value, and returns the resultant string.
*
* @param key the key associated with the desired property
* @param defaultValue the default value to return if the property is not found or is null
* @return the string property without surrounding quotes, or the defaultValue if the property is not found
*/
protected String getStringPropertyWithoutQuotes(final String key, final String defaultValue) {
return Strings.removeQuotes(getStringProperty(key, defaultValue));
}
/**
* Retrieves the string value of a configuration property identified by the given key,
* removes surrounding quotes if present, and expands any environment variables found
* within the string. If the property is not found, a default value is used.
*
* @param key the key identifying the configuration property
* @param key the key identifying the configuration property
* @param defaultValue the default value to use if the property is not found
* @return the processed string property with quotes removed and environment variables expanded
*/
@@ -118,16 +106,28 @@ public class Configuration {
return Strings.expandEnvironmentVariables(result);
}
/**
* Retrieves the value of a string property associated with the specified key,
* removes any surrounding quotes from the value, and returns the resultant string.
*
* @param key the key associated with the desired property
* @param defaultValue the default value to return if the property is not found or is null
* @return the string property without surrounding quotes, or the defaultValue if the property is not found
*/
protected String getStringPropertyWithoutQuotes(final String key, final String defaultValue) {
return Strings.removeQuotes(getStringProperty(key, defaultValue));
}
/**
* Retrieves the integer value for the specified property key. If the key does
* not exist in the properties or the value is null/empty, the provided default
* value is returned.
*
* @param key the property key to retrieve the value for
* @param key the property key to retrieve the value for
* @param defaultValue the default value to return if the key is not present
* or the value is null/empty
* @return the integer value associated with the key, or the defaultValue if
* the key does not exist or its value is null/empty
* the key does not exist or its value is null/empty
*/
protected Integer getIntegerProperty(final String key, final Integer defaultValue) {
if (!properties.containsKey(key)) return defaultValue;
@@ -139,14 +139,14 @@ public class Configuration {
* Sets an integer property in the properties object. If the provided value is null,
* an empty string will be stored as the property's value.
*
* @param key the key under which the property will be stored
* @param key the key under which the property will be stored
* @param value the integer value to be stored; if null, an empty string will be used
*/
protected void setIntegerProperty(final String key, final Integer value) {
if (value == null) {
properties.setProperty(key, "");
} else {
properties.setProperty(key, ""+value);
properties.setProperty(key, "" + value);
}
}
@@ -154,11 +154,11 @@ public class Configuration {
* Retrieves a LocalDate value from the properties based on the provided key.
* If the key does not exist or the value is invalid, a default value is returned.
*
* @param key the key to look up the property in the properties map
* @param key the key to look up the property in the properties map
* @param defaultValue the default LocalDate value to return if the key is not found
* @param formatString the format string to parse the LocalDate value
* @return the LocalDate value from the properties if available and valid,
* otherwise the defaultValue
* otherwise the defaultValue
*/
protected LocalDate getLocalDateProperty(final String key, final LocalDate defaultValue, final String formatString) {
if (!properties.containsKey(key)) return defaultValue;
@@ -172,8 +172,8 @@ public class Configuration {
* Sets a property with the given key and a formatted LocalDate value.
* If the provided value is null, the property will be set to an empty string.
*
* @param key the key of the property to set
* @param value the LocalDate value to format and set as the property value
* @param key the key of the property to set
* @param value the LocalDate value to format and set as the property value
* @param formatString the pattern string used to format the LocalDate value
*/
protected void setLocalDateProperty(final String key, final LocalDate value, final String formatString) {
@@ -188,7 +188,7 @@ public class Configuration {
* Sets a property with the specified key to the given value. If the value is null,
* it defaults to an empty string. Logs the operation and updates the property.
*
* @param key the key of the property to be set
* @param key the key of the property to be set
* @param value the value to be associated with the specified key; defaults to an empty string if null
*/
public void setProperty(final String key, final String value) {
@@ -211,9 +211,9 @@ public class Configuration {
* specified location, it attempts to find the file alongside the JAR file of the application.
* Reads the configuration with the provided encoding and an option to accept UTF-8 encoding.
*
* @param fileName the name of the configuration file to be loaded
* @param encoding the encoding format to be used while reading the configuration file
* @param acceptUTF8 a boolean flag indicating whether to accept UTF-8 encoding
* @param fileName the name of the configuration file to be loaded
* @param encoding the encoding format to be used while reading the configuration file
* @param acceptUTF8 a boolean flag indicating whether to accept UTF-8 encoding
*/
public void load(final String fileName, final String encoding, final boolean acceptUTF8) {
log.info("Reading Config: " + fileName + " with encoding: " + encoding + "accepting UTF-8: " + acceptUTF8);
@@ -251,7 +251,7 @@ public class Configuration {
* @param config the Configuration object whose properties will be merged into this instance
*/
public void merge(final Configuration config) {
for(Map.Entry<Object, Object> entry: config.properties.entrySet()) {
for (Map.Entry<Object, Object> entry : config.properties.entrySet()) {
properties.put(entry.getKey(), entry.getValue());
}
}
@@ -261,7 +261,7 @@ public class Configuration {
*
* @param key the key to be removed from the properties map
*/
public void remove(final String key){
public void remove(final String key) {
if (properties.containsKey(key)) properties.remove(key);
}
}
@@ -1,6 +1,5 @@
package de.neitzel.core.io;
import de.neitzel.core.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
@@ -12,7 +11,7 @@ import java.nio.charset.IllegalCharsetNameException;
* for handling file encoding conversion transparently. If a file is detected to be in UTF-8 encoding,
* this class converts it to the specified target encoding using a temporary file, then opens the reader
* with the converted encoding. If the file is already in the target encoding, it opens the reader directly.
*
* <p>
* This class is useful for applications needing to process text files in specific encodings and ensures
* encoding compatibility.
*/
@@ -25,47 +24,19 @@ public class ConvertedEncodingFileReader extends InputStreamReader {
* This encoding is primarily used to determine whether a file needs conversion
* to the target format or can be read directly in its existing format.
* The default value is set to "ISO-8859-15".
*
* <p>
* Modifying this variable requires careful consideration, as it affects
* the behavior of methods that rely on encoding validation, particularly
* in the process of detecting UTF-8 files or converting them during file reading.
*/
private static String checkEncoding = "ISO-8859-15";
/**
* Sets the encoding that will be used to check the file encoding for compatibility.
* Throws an exception if the specified encoding is not valid or supported.
*
* @param encoding the name of the character encoding to set as the check encoding;
* it must be a valid and supported Charset.
* @throws IllegalCharsetNameException if the specified encoding is not valid or supported.
*/
private static void setCheckEncoding(final String encoding) {
if (Charset.forName(encoding) != null) throw new IllegalCharsetNameException("Encoding " + encoding + " is not supported!");
checkEncoding = encoding;
}
/**
* Constructs a ConvertedEncodingFileReader for a specified file and target encoding format.
* The class reads the provided file and ensures that its content is handled in the target encoding.
* If the file is not already in the target encoding, it converts the file's encoding
* transparently using a temporary file before reading it.
*
* @param file The file to be read. Must exist and be accessible.
* @param targetFormat The target character encoding format to which the file content should be converted.
* @throws IOException If the file does not exist, is inaccessible, or an error occurs during the encoding conversion process.
*/
public ConvertedEncodingFileReader(final File file, final String targetFormat) throws IOException {
super(createTargetFormatInputFileStream(file, targetFormat), targetFormat);
}
/**
* Constructs a ConvertedEncodingFileReader for reading a file with encoding conversion support.
* This constructor takes the file path as a string and ensures the file's encoding is either
* converted to the specified target format or read directly if it matches the target format.
*
* @param filename the path to the file to be read
* @param filename the path to the file to be read
* @param targetFormat the target encoding format to use for reading the file
* @throws IOException if an I/O error occurs while accessing or reading the specified file
*/
@@ -73,13 +44,27 @@ public class ConvertedEncodingFileReader extends InputStreamReader {
this(new File(filename), targetFormat);
}
/**
* Constructs a ConvertedEncodingFileReader for a specified file and target encoding format.
* The class reads the provided file and ensures that its content is handled in the target encoding.
* If the file is not already in the target encoding, it converts the file's encoding
* transparently using a temporary file before reading it.
*
* @param file The file to be read. Must exist and be accessible.
* @param targetFormat The target character encoding format to which the file content should be converted.
* @throws IOException If the file does not exist, is inaccessible, or an error occurs during the encoding conversion process.
*/
public ConvertedEncodingFileReader(final File file, final String targetFormat) throws IOException {
super(createTargetFormatInputFileStream(file, targetFormat), targetFormat);
}
/**
* Creates an input file stream for a given file, converting its encoding if necessary.
* If the file is not in UTF-8 encoding, a direct {@link FileInputStream} is returned for the file.
* If the file is in UTF-8 encoding, it is converted to the specified target format using a temporary file,
* and then an input stream for the temporary file is returned.
*
* @param file the file for which the input stream is to be created
* @param file the file for which the input stream is to be created
* @param targetFormat the desired target encoding format
* @return a {@link FileInputStream} for the file or a temporary file with converted encoding
* @throws IOException if the file does not exist or an error occurs during file operations
@@ -100,4 +85,19 @@ public class ConvertedEncodingFileReader extends InputStreamReader {
return new FileInputStream(tempFile);
}
}
/**
* Sets the encoding that will be used to check the file encoding for compatibility.
* Throws an exception if the specified encoding is not valid or supported.
*
* @param encoding the name of the character encoding to set as the check encoding;
* it must be a valid and supported Charset.
* @throws IllegalCharsetNameException if the specified encoding is not valid or supported.
*/
private static void setCheckEncoding(final String encoding) {
if (Charset.forName(encoding) != null)
throw new IllegalCharsetNameException("Encoding " + encoding + " is not supported!");
checkEncoding = encoding;
}
}
@@ -1,31 +1,21 @@
package de.neitzel.core.util;
package de.neitzel.core.io;
import de.neitzel.core.util.ArrayUtils;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.stream.Collectors;
/**
* Utility class for handling file operations, such as encoding checks, content reading/writing,
* path manipulations, and file conversions.
* A utility class for file-related operations. This class provides functionalities
* for handling files and directories in an efficient manner.
*/
@Slf4j
public class FileUtils {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private FileUtils() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Defines a standardized timestamp format for debugging purposes, specifically used for naming
* or identifying files with precise timestamps. The format is "yyyy-MM-dd_HH_mm_ss_SSS", which
@@ -37,14 +27,14 @@ public class FileUtils {
* - Minutes in two digits (mm)
* - Seconds in two digits (ss)
* - Milliseconds in three digits (SSS)
*
* <p>
* This ensures timestamps are sortable and easily identifiable.
*/
public static final SimpleDateFormat DEBUG_FILE_TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss_SSS");
/**
* Default encoding used for string checks and validations in the application.
*
* <p>
* This constant represents the `ISO-8859-15` encoding, which is a standardized
* character set encoding, commonly used in contexts where backward compatibility
* with `ISO-8859-1` is required, but with support for certain additional characters,
@@ -54,17 +44,40 @@ public class FileUtils {
/**
* Specifies the default buffer size used for data processing operations.
*
* <p>
* This constant represents the size of the buffer in bytes, set to 1024,
* and is typically utilized in input/output operations to optimize performance
* by reducing the number of read/write calls.
*/
public static final int BUFFER_SIZE = 1024;
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private FileUtils() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Determines if the content of the given file is encoded in UTF-8.
*
* @param file The file to check for UTF-8 encoding. Must not be null.
* @return true if the file content is in UTF-8 encoding; false otherwise.
* @throws IOException If an I/O error occurs while reading the file.
*/
public static boolean isUTF8(final File file) throws IOException {
return isUTF8(file, DEFAULT_CHECK_ENCODING);
}
/**
* Determines whether the given file is encoded in UTF-8.
*
* @param file The file to be checked for UTF-8 encoding.
* @param file The file to be checked for UTF-8 encoding.
* @param checkEncoding The character encoding to use while checking the file content.
* @return true if the file is determined to be encoded in UTF-8; false otherwise.
* @throws IOException If an I/O error occurs while reading the file.
@@ -82,7 +95,7 @@ public class FileUtils {
if (
(ArrayUtils.contains(buffer, (char) 0x00C2)) // Part of UTF-8 Characters 0xC2 0xZZ
|| (ArrayUtils.contains(buffer, (char) 0x00C3))) { // Part of UTF-8 Characters 0xC3 0xZZ
|| (ArrayUtils.contains(buffer, (char) 0x00C3))) { // Part of UTF-8 Characters 0xC3 0xZZ
return true;
}
@@ -97,7 +110,7 @@ public class FileUtils {
/**
* Checks if the provided file starts with a UTF-8 Byte Order Mark (BOM).
*
* <p>
* This method reads the first character of the file using a reader that assumes
* UTF-8 encoding and checks if it matches the Unicode Byte Order Mark (U+FEFF).
*
@@ -114,26 +127,15 @@ public class FileUtils {
}
}
/**
* Determines if the content of the given file is encoded in UTF-8.
*
* @param file The file to check for UTF-8 encoding. Must not be null.
* @return true if the file content is in UTF-8 encoding; false otherwise.
* @throws IOException If an I/O error occurs while reading the file.
*/
public static boolean isUTF8(final File file) throws IOException {
return isUTF8(file, DEFAULT_CHECK_ENCODING);
}
/**
* Converts the content of a text file from one character encoding format to another.
*
* <p>
* This method reads the input text file using the specified source encoding and writes
* the content to the output text file in the specified target encoding.
*
* @param inFile The input text file to be converted. Must not be null.
* @param inFile The input text file to be converted. Must not be null.
* @param sourceFormat The character encoding of the input file. Must not be null or empty.
* @param outFile The output text file to write the converted content to. Must not be null.
* @param outFile The output text file to write the converted content to. Must not be null.
* @param targetFormat The character encoding to be used for the output file. Must not be null or empty.
* @throws IOException If an I/O error occurs during reading or writing.
*/
@@ -167,25 +169,12 @@ public class FileUtils {
}
}
/**
* Creates a universal file reader for the specified file name.
* This method initializes and returns an InputStreamReader to read
* the content of the given file.
*
* @param filename The name or path of the file to be read.
* @return An InputStreamReader for reading the specified file.
* @throws IOException If an I/O error occurs while creating the file reader.
*/
public static InputStreamReader createUniversalFileReader(final String filename) throws IOException {
return createUniversalFileReader(new File(filename));
}
/**
* Creates a universal file reader for the specified file and format.
* The method resolves the file using its name and the expected format,
* returning an InputStreamReader for reading the file contents.
*
* @param filename the name of the file to be read.
* @param filename the name of the file to be read.
* @param expectedFormat the format expected for the file content.
* @return an InputStreamReader for the specified file and format.
* @throws IOException if an I/O error occurs while opening or reading the file.
@@ -194,25 +183,14 @@ public class FileUtils {
return createUniversalFileReader(new File(filename), expectedFormat);
}
/**
* Creates a universal file reader for the specified file using the default encoding and configuration.
*
* @param file The file to be read. Must not be null.
* @return An InputStreamReader configured to read the specified file.
* @throws IOException If an I/O error occurs while creating the reader.
*/
public static InputStreamReader createUniversalFileReader(final File file) throws IOException {
return createUniversalFileReader(file, DEFAULT_CHECK_ENCODING, true);
}
/**
* Creates a universal file reader for the specified file with an expected format.
* This method wraps the given file in an InputStreamReader for consistent character stream manipulation.
*
* @param file The file to be read. Must not be null.
* @param file The file to be read. Must not be null.
* @param expectedFormat The expected format of the file (e.g., encoding). Must not be null.
* @return An InputStreamReader for the specified file, allowing the caller to read the file
* with the desired format applied.
* with the desired format applied.
* @throws IOException If an I/O error occurs during the creation of the reader.
*/
public static InputStreamReader createUniversalFileReader(final File file, final String expectedFormat) throws IOException {
@@ -223,9 +201,9 @@ public class FileUtils {
* Creates an InputStreamReader for reading a file, considering the specified encoding format
* and whether UTF-8 should be accepted. Handles potential BOM for UTF-8 encoded files.
*
* @param file The file to be read.
* @param file The file to be read.
* @param expectedFormat The expected encoding format of the file.
* @param acceptUTF8 Indicates whether UTF-8 encoding should be accepted if detected.
* @param acceptUTF8 Indicates whether UTF-8 encoding should be accepted if detected.
* @return An InputStreamReader for the specified file and encoding.
* @throws IOException If there is an error accessing the file or reading its content.
*/
@@ -239,14 +217,14 @@ public class FileUtils {
InputStreamReader result = new InputStreamReader(new FileInputStream(file), encoding);
if (skipBOM) {
int BOM = result.read();
if (BOM != 0xFEFF) log.error ("Skipping BOM but value not 0xFEFF!");
if (BOM != 0xFEFF) log.error("Skipping BOM but value not 0xFEFF!");
}
return result;
}
/**
* Retrieves the parent directory of the given file or directory path.
*
* <p>
* If the given path does not have a parent directory, it defaults to returning the
* current directory represented by ".".
*
@@ -282,10 +260,34 @@ public class FileUtils {
}
}
/**
* Creates a universal file reader for the specified file name.
* This method initializes and returns an InputStreamReader to read
* the content of the given file.
*
* @param filename The name or path of the file to be read.
* @return An InputStreamReader for reading the specified file.
* @throws IOException If an I/O error occurs while creating the file reader.
*/
public static InputStreamReader createUniversalFileReader(final String filename) throws IOException {
return createUniversalFileReader(new File(filename));
}
/**
* Creates a universal file reader for the specified file using the default encoding and configuration.
*
* @param file The file to be read. Must not be null.
* @return An InputStreamReader configured to read the specified file.
* @throws IOException If an I/O error occurs while creating the reader.
*/
public static InputStreamReader createUniversalFileReader(final File file) throws IOException {
return createUniversalFileReader(file, DEFAULT_CHECK_ENCODING, true);
}
/**
* Writes the given content to the specified file path. If the file already exists, it will be overwritten.
*
* @param path The path of the file to write to. Must not be null and must be writable.
* @param path The path of the file to write to. Must not be null and must be writable.
* @param content The content to be written to the file. Must not be null.
* @throws IOException If an I/O error occurs during writing to the file.
*/
@@ -294,4 +296,60 @@ public class FileUtils {
writer.write(content);
}
}
/**
* Deletes the specified file or directory. If the target is a directory, all its contents,
* including subdirectories and files, will be deleted recursively.
* If the target file or directory does not exist, the method immediately returns {@code true}.
*
* @param targetFile the {@code Path} of the file or directory to be deleted
* @return {@code true} if the target file or directory was successfully deleted,
* or if it does not exist; {@code false} if an error occurred during deletion
*/
public static boolean remove(Path targetFile) {
if (!Files.exists(targetFile)) {
return true;
}
if (Files.isDirectory(targetFile)) {
return removeDirectory(targetFile);
}
return targetFile.toFile().delete();
}
/**
* Deletes the specified directory and all its contents, including subdirectories and files.
* The method performs a recursive deletion, starting with the deepest entries in the directory tree.
* If the directory does not exist, the method immediately returns true.
*
* @param targetDir the {@code Path} of the directory to be deleted
* @return {@code true} if the directory and all its contents were successfully deleted
* or if the directory does not exist; {@code false} if an error occurred during deletion
*/
public static boolean removeDirectory(Path targetDir) {
if (!Files.exists(targetDir)) {
return true;
}
if (!Files.isDirectory(targetDir)) {
return false;
}
try {
Files.walk(targetDir)
.sorted((a, b) -> b.compareTo(a))
.forEach(path -> {
try {
Files.deleteIfExists(path);
} catch (Exception ignored) {
}
});
} catch (IOException ignored) {
return false;
}
return true;
}
}
@@ -0,0 +1,76 @@
package de.neitzel.core.io;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.stream.Stream;
/**
* A utility class for creating and managing a temporary directory.
* Instances of this class create a unique temporary directory on the filesystem
* that can safely be used during the runtime of a program.
* <p>
* The directory is automatically cleaned up when the instance is closed.
*/
public class TempDirectory implements AutoCloseable {
/**
* The filesystem path representing the temporary directory managed by this instance.
* This path is initialized when the TempDirectory object is created and points
* to a unique, newly created directory.
* <p>
* The directory can be used to safely store temporary runtime files. It is automatically
* deleted along with its content when the associated TempDirectory object is closed.
*/
private final Path directory;
/**
* Creates a temporary directory with a unique name on the filesystem.
* The directory will have a prefix specified by the user and is intended
* to serve as a temporary workspace during the runtime of the program.
*
* @param prefix the prefix to be used for the name of the temporary directory
* @throws IOException if an I/O error occurs when creating the directory
*/
public TempDirectory(String prefix) throws IOException {
this.directory = Files.createTempDirectory(prefix);
}
/**
* Retrieves the path of the temporary directory associated with this instance.
*
* @return the {@code Path} of the temporary directory
*/
public Path getDirectory() {
return directory;
}
/**
* Closes the temporary directory by cleaning up its contents and deleting the directory itself.
* <p>
* This method ensures that all files and subdirectories within the temporary directory are
* deleted in a reverse order, starting from the deepest leaf in the directory tree. If
* the directory does not exist, the method will not perform any actions.
* <p>
* If an error occurs while deleting any file or directory, a RuntimeException is thrown
* with the details of the failure.
*
* @throws IOException if an I/O error occurs while accessing the directory or its contents.
*/
@Override
public void close() throws IOException {
if (Files.exists(directory)) {
try (Stream<Path> walk = Files.walk(directory)) {
walk.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
throw new RuntimeException("Failed to delete: " + path, e);
}
});
}
}
}
}