sirius.kernel.commons.Files Maven / Gradle / Ivy
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.kernel.commons;
import sirius.kernel.health.Exceptions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Optional;
import java.util.regex.Pattern;
/**
* Helperclass for handling files in Java 8.
*/
public class Files {
private static final Pattern NON_PATH_CHARACTERS = Pattern.compile("[^a-zA-Z0-9\\-.]");
private Files() {
}
/**
* Converts the given string to a valid and sane filename.
*
* The result will only consist of letters, digits '-' and '_'. Everything else will be
* replaced by a '_'. German umlauts like 'ä', 'ö', 'ü' are replaced the appropriate
* ASCII sequences.
*
* @param input the filename to fix
* @return the transformed filename wrapped as Optional or an empty Optional if the filename is not filled
*/
@Nonnull
public static Optional toSaneFileName(@Nullable String input) {
String effectiveInput = Strings.trim(Strings.reduceCharacters(input));
if (Strings.isEmpty(effectiveInput)) {
return Optional.empty();
}
effectiveInput = NON_PATH_CHARACTERS.matcher(effectiveInput).replaceAll("_");
Tuple nameAndSuffix = Strings.splitAtLast(effectiveInput, ".");
if (nameAndSuffix.getSecond() == null) {
return Optional.of(effectiveInput);
}
return Optional.of(nameAndSuffix.getFirst().replace(".", "_") + "." + nameAndSuffix.getSecond());
}
/**
* Returns the file extension of the given path or filename.
*
* A path could be /dir/foo/test.txt, a filename would be test.txt.
*
* @param path the path to parse
* @return the file extension (txt for test.txt) without the leading dot. Returns null if
* the input is empty or does not contain a file extension. The a file contains several extensions, like
* .txt.zip, only the last is returned.
*/
@Nullable
public static String getFileExtension(@Nullable String path) {
return Strings.splitAtLast(path, ".").getSecond();
}
/**
* Returns the basepath of the given path to a file.
*
* The basepath is everything but the filename of the given path. So /foo/bar/test.txt
* will yield /foo/bar as as path. text.txt will yield null.
*
* Note that both / and \ are accepted as path separators and are preserved in the output.
*
* @param path the path to a file to parse
* @return the path part of the given path, which is everything but the last separator and the filename. Returns
* null if the given path is empty or does not contain a path.
*/
@Nullable
public static String getBasepath(@Nullable String path) {
if (Strings.isEmpty(path)) {
return null;
}
int lastPathSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
if (lastPathSeparator <= 0) {
return null;
}
return path.substring(0, lastPathSeparator);
}
/**
* Returns the filename with the file extension of the given path.
*
* The filename is everything after the last separator (/ or \). If the given path
* does not contain a separator, the whole path will be returned.
*
* @param path the path to a file to parse
* @return the filename without the path to it. Returns null if the input is empty or null.
*/
@Nullable
public static String getFilenameAndExtension(@Nullable String path) {
if (Strings.isEmpty(path)) {
return null;
}
int lastPathSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
if (lastPathSeparator < 0) {
return path;
}
if (lastPathSeparator == path.length() - 1) {
return null;
}
return path.substring(lastPathSeparator + 1);
}
/**
* Returns the filename without its file extension.
*
* The file extension is everything after the last . in the filename.
*
* @param path the path to a file to parse
* @return the filename without extension or null if the given path is empty, null or does not
* have a filename (ends with a sepratator).
*/
@Nullable
public static String getFilenameWithoutExtension(@Nullable String path) {
return Strings.splitAtLast(getFilenameAndExtension(path), ".").getFirst();
}
/**
* If the given file is not null and exists, tries to delete that file and logs when a file cannot be deleted. T
* his is useful for error reporting and to diagnose why a file cannot be deleted.
*
* @param file the file to delete
*/
public static void delete(@Nullable File file) {
if (file != null) {
try {
java.nio.file.Files.deleteIfExists(file.toPath());
} catch (IOException e) {
Exceptions.handle(e);
}
}
}
/**
* Deletes the given directory structure including all sub directories.
*
* @param directory the directory to delete (along with all sub directories)
* @throws IOException in case of an io error while deleting the files and directories
*/
public static void delete(Path directory) throws IOException {
if (!directory.toFile().exists()) {
return;
}
java.nio.file.Files.walkFileTree(directory, new SimpleFileVisitor() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
java.nio.file.Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
java.nio.file.Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Removes all children (files and directories) of the given directory.
*
* @param directory the containing the children to delete (along with all sub directories)
* @throws IOException in case of an io error while deleting the files and directories
*/
public static void removeChildren(Path directory) throws IOException {
java.nio.file.Files.walkFileTree(directory, new SimpleFileVisitor() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
java.nio.file.Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (!dir.equals(directory)) {
java.nio.file.Files.delete(dir);
}
return FileVisitResult.CONTINUE;
}
});
}
}