删除 FileUtils 中基于 java.io.File 的工具方法 (#4493)

This commit is contained in:
Glavo
2025-09-16 20:52:44 +08:00
committed by GitHub
parent b328ed2cc9
commit fc1cce5e5a
24 changed files with 108 additions and 246 deletions

View File

@@ -47,6 +47,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.time.Instant;
import java.util.*;
@@ -92,11 +93,13 @@ public class HMCLGameRepository extends DefaultGameRepository {
case ROOT_FOLDER:
return super.getRunDirectory(id);
case CUSTOM:
File dir = new File(getVersionSetting(id).getGameDir());
if (!FileUtils.isValidPath(dir)) return getVersionRoot(id);
return dir;
try {
return Path.of(getVersionSetting(id).getGameDir()).toFile();
} catch (InvalidPathException ignored) {
return getVersionRoot(id);
}
default:
throw new Error();
throw new AssertionError("Unreachable");
}
}
@@ -119,9 +122,11 @@ public class HMCLGameRepository extends DefaultGameRepository {
});
try {
File file = new File(getBaseDirectory(), "launcher_profiles.json");
if (!file.exists() && !versions.isEmpty())
FileUtils.writeText(file, PROFILE);
Path file = getBaseDirectory().toPath().resolve("launcher_profiles.json");
if (!Files.exists(file) && !versions.isEmpty()) {
Files.createDirectories(file.getParent());
Files.writeString(file, PROFILE);
}
} catch (IOException ex) {
LOG.warning("Unable to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex);
}
@@ -132,14 +137,14 @@ public class HMCLGameRepository extends DefaultGameRepository {
refreshVersionsAsync().start();
}
private void clean(File directory) throws IOException {
FileUtils.deleteDirectory(new File(directory, "crash-reports"));
FileUtils.deleteDirectory(new File(directory, "logs"));
private void clean(Path directory) throws IOException {
FileUtils.deleteDirectory(directory.resolve("crash-reports"));
FileUtils.deleteDirectory(directory.resolve("logs"));
}
public void clean(String id) throws IOException {
clean(getBaseDirectory());
clean(getRunDirectory(id));
clean(getBaseDirectory().toPath());
clean(getRunDirectory(id).toPath());
}
public void duplicateVersion(String srcId, String dstId, boolean copySaves) throws IOException {
@@ -270,14 +275,14 @@ public class HMCLGameRepository extends DefaultGameRepository {
}
public void setVersionIconFile(String id, File iconFile) throws IOException {
String ext = FileUtils.getExtension(iconFile).toLowerCase(Locale.ROOT);
String ext = FileUtils.getExtension(iconFile.getName()).toLowerCase(Locale.ROOT);
if (!FXUtils.IMAGE_EXTENSIONS.contains(ext)) {
throw new IllegalArgumentException("Unsupported icon file: " + ext);
}
deleteIconFile(id);
FileUtils.copyFile(iconFile, new File(getVersionRoot(id), "icon." + ext));
FileUtils.copyFile(iconFile.toPath(), getVersionRoot(id).toPath().resolve("icon." + ext));
}
public void deleteIconFile(String id) {

View File

@@ -81,7 +81,7 @@ public final class ModpackHelper {
}
public static boolean isFileModpackByExtension(File file) {
String ext = FileUtils.getExtension(file);
String ext = FileUtils.getExtension(file.getName());
return "zip".equals(ext) || "mrpack".equals(ext);
}

View File

@@ -207,7 +207,7 @@ public final class HMCLJavaRepository implements JavaRepository {
public Task<Void> getUninstallJavaTask(Platform platform, String name) {
return Task.runAsync(() -> {
Files.deleteIfExists(getManifestFile(platform, name));
FileUtils.deleteDirectory(getJavaDir(platform, name).toFile());
FileUtils.deleteDirectory(getJavaDir(platform, name));
});
}
@@ -220,7 +220,7 @@ public final class HMCLJavaRepository implements JavaRepository {
if (relativized.getNameCount() > 1) {
String name = relativized.getName(0).toString();
Files.deleteIfExists(getManifestFile(java.getPlatform(), name));
FileUtils.deleteDirectory(getJavaDir(java.getPlatform(), name).toFile());
FileUtils.deleteDirectory(getJavaDir(java.getPlatform(), name));
}
});
}

View File

@@ -460,8 +460,10 @@ public final class FXUtils {
}
public static void openFolder(File file) {
if (!FileUtils.makeDirectory(file)) {
LOG.error("Unable to make directory " + file);
try {
Files.createDirectories(file.toPath());
} catch (IOException e) {
LOG.warning("Failed to create directory " + file);
return;
}

View File

@@ -114,7 +114,7 @@ public final class LocalModpackPage extends ModpackPage {
if (!name.isPresent()) {
// trim: https://github.com/HMCL-dev/HMCL/issues/962
txtModpackName.setText(FileUtils.getNameWithoutExtension(selectedFile));
txtModpackName.setText(FileUtils.getNameWithoutExtension(selectedFile.getName()));
}
Controllers.confirm(i18n("modpack.type.manual.warning"), i18n("install.modpack"), MessageDialogPane.MessageType.WARNING,

View File

@@ -87,8 +87,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED;
if (basePath.length() > "minecraft/".length()) {
state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (file.isDirectory() ? "/" : ""), file.isDirectory());
if (file.isFile() && Objects.equals(FileUtils.getNameWithoutExtension(file), version)) // Ignore <version>.json, <version>.jar
state = ModAdviser.ModSuggestion.HIDDEN;
if (file.isFile() && Objects.equals(FileUtils.getNameWithoutExtension(file.getName()), version)) state = ModAdviser.ModSuggestion.HIDDEN;
if (file.isDirectory() && Objects.equals(file.getName(), version + "-natives")) // Ignore <version>-natives
state = ModAdviser.ModSuggestion.HIDDEN;
if (state == ModAdviser.ModSuggestion.HIDDEN)

View File

@@ -38,7 +38,6 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.tukaani.xz.XZInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -254,6 +253,9 @@ public final class SettingsPage extends SettingsView {
@Override
protected void clearCacheDirectory() {
FileUtils.cleanDirectoryQuietly(new File(Settings.instance().getCommonDirectory(), "cache"));
String commonDirectory = Settings.instance().getCommonDirectory();
if (commonDirectory != null) {
FileUtils.cleanDirectoryQuietly(Path.of(commonDirectory, "cache"));
}
}
}

View File

@@ -50,7 +50,7 @@ public final class DatapackListPage extends ListPageBase<DatapackListPageSkin.Da
setItems(MappedObservableList.create(datapack.getInfo(), DatapackListPageSkin.DatapackInfoObject::new));
FXUtils.applyDragListener(this, it -> Objects.equals("zip", FileUtils.getExtension(it)),
FXUtils.applyDragListener(this, it -> Objects.equals("zip", FileUtils.getExtension(it.getName())),
mods -> mods.forEach(this::installSingleDatapack), this::refresh);
}

View File

@@ -49,7 +49,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
private String gameVersion;
{
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "exe").contains(FileUtils.getExtension(it)), mods -> {
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "exe").contains(FileUtils.getExtension(it.getName())), mods -> {
if (!mods.isEmpty())
doInstallOffline(mods.get(0));
});

View File

@@ -59,7 +59,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
private String versionId;
public ModListPage() {
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "zip", "litemod").contains(FileUtils.getExtension(it)), mods -> {
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "zip", "litemod").contains(FileUtils.getExtension(it.getName())), mods -> {
mods.forEach(it -> {
try {
modManager.addMod(it.toPath());

View File

@@ -373,7 +373,7 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
@Override
void onDelete() {
try {
FileUtils.cleanDirectory(path.toFile());
FileUtils.cleanDirectory(path);
Files.deleteIfExists(path);
refresh();
} catch (IOException e) {

View File

@@ -166,14 +166,14 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage
}
private void clearLibraries() {
FileUtils.deleteDirectoryQuietly(new File(getProfile().getRepository().getBaseDirectory(), "libraries"));
FileUtils.deleteDirectoryQuietly(getProfile().getRepository().getBaseDirectory().toPath().resolve("libraries"));
}
private void clearAssets() {
HMCLGameRepository baseDirectory = getProfile().getRepository();
FileUtils.deleteDirectoryQuietly(new File(baseDirectory.getBaseDirectory(), "assets"));
FileUtils.deleteDirectoryQuietly(baseDirectory.getBaseDirectory().toPath().resolve("assets"));
if (version.get() != null) {
FileUtils.deleteDirectoryQuietly(new File(baseDirectory.getRunDirectory(version.get().getVersion()), "resources"));
FileUtils.deleteDirectoryQuietly(baseDirectory.getRunDirectory(version.get().getVersion()).toPath().resolve("resources"));
}
}

View File

@@ -53,7 +53,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
private String gameVersion;
public WorldListPage() {
FXUtils.applyDragListener(this, it -> "zip".equals(FileUtils.getExtension(it)), modpacks -> {
FXUtils.applyDragListener(this, it -> "zip".equals(FileUtils.getExtension(it.getName())), modpacks -> {
installWorld(modpacks.get(0));
});

View File

@@ -421,6 +421,6 @@ public class ForgeNewInstallTask extends Task<Version> {
@Override
public void postExecute() throws Exception {
FileUtils.deleteDirectory(tempDir.toFile());
FileUtils.deleteDirectory(tempDir);
}
}

View File

@@ -24,10 +24,11 @@ import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
@@ -71,12 +72,12 @@ public class ForgeOldInstallTask extends Task<Version> {
// unpack the universal jar in the installer file.
Library forgeLibrary = new Library(installProfile.getInstall().getPath());
File forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary);
if (!FileUtils.makeFile(forgeFile))
throw new IOException("Cannot make directory " + forgeFile.getParent());
Path forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary).toPath();
Files.createDirectories(forgeFile.getParent());
ZipEntry forgeEntry = zipFile.getEntry(installProfile.getInstall().getFilePath());
try (InputStream is = zipFile.getInputStream(forgeEntry); OutputStream os = new FileOutputStream(forgeFile)) {
try (InputStream is = zipFile.getInputStream(forgeEntry);
OutputStream os = Files.newOutputStream(forgeFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
is.transferTo(os);
}

View File

@@ -103,7 +103,7 @@ public final class GameLibrariesTask extends Task<Void> {
if (library.getChecksums() != null && !library.getChecksums().isEmpty() && !LibraryDownloadTask.checksumValid(file, library.getChecksums())) {
return true;
}
if (FileUtils.getExtension(file).equals("jar")) {
if (FileUtils.getExtension(file.getName()).equals("jar")) {
try {
FileDownloadTask.ZIP_INTEGRITY_CHECK_HANDLER.checkIntegrity(jar, jar);
} catch (IOException ignored) {

View File

@@ -105,7 +105,7 @@ public class LibraryDownloadTask extends Task<Void> {
Optional<Path> libPath = cacheRepository.getLibrary(originalLibrary);
if (libPath.isPresent()) {
try {
FileUtils.copyFile(libPath.get().toFile(), jar);
FileUtils.copyFile(libPath.get(), jar.toPath());
cached = true;
return;
} catch (IOException e) {

View File

@@ -417,6 +417,6 @@ public class NeoForgeOldInstallTask extends Task<Version> {
@Override
public void postExecute() throws Exception {
FileUtils.deleteDirectory(tempDir.toFile());
FileUtils.deleteDirectory(tempDir);
}
}

View File

@@ -167,7 +167,7 @@ public final class OptiFineInstallTask extends Task<Version> {
if (Files.exists(launchWrapper2)) {
Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper", "2.0"));
File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
FileUtils.makeDirectory(launchWrapperFile.getAbsoluteFile().getParentFile());
Files.createDirectories(launchWrapperFile.toPath().toAbsolutePath().getParent());
FileUtils.copyFile(launchWrapper2, launchWrapperFile.toPath());
hasLaunchWrapper = true;
libraries.add(launchWrapper);
@@ -182,7 +182,7 @@ public final class OptiFineInstallTask extends Task<Version> {
if (Files.exists(launchWrapperJar)) {
File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
FileUtils.makeDirectory(launchWrapperFile.getAbsoluteFile().getParentFile());
Files.createDirectories(launchWrapperFile.toPath().toAbsolutePath().getParent());
FileUtils.copyFile(launchWrapperJar, launchWrapperFile.toPath());
hasLaunchWrapper = true;

View File

@@ -214,7 +214,7 @@ public class DefaultGameRepository implements GameRepository {
if (fromVersion.getId().equals(fromVersion.getJar()))
fromVersion = fromVersion.setJar(null);
FileUtils.writeText(toJson, JsonUtils.GSON.toJson(fromVersion.setId(to)));
JsonUtils.writeToJsonFile(toJson, fromVersion.setId(to));
// fix inheritsFrom of versions that inherits from version [from].
for (Version version : getVersions()) {
@@ -235,7 +235,7 @@ public class DefaultGameRepository implements GameRepository {
if (EventBus.EVENT_BUS.fireEvent(new RemoveVersionEvent(this, id)) == Event.Result.DENY)
return false;
if (!versions.containsKey(id))
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id));
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id).toPath());
File file = getVersionRoot(id);
if (!file.exists())
return true;
@@ -247,19 +247,23 @@ public class DefaultGameRepository implements GameRepository {
try {
versions.remove(id);
if (FileUtils.moveToTrash(removedFile)) {
if (FileUtils.moveToTrash(removedFile.toPath())) {
return true;
}
// remove json files first to ensure HMCL will not recognize this folder as a valid version.
List<File> jsons = FileUtils.listFilesByExtension(removedFile, "json");
jsons.forEach(f -> {
if (!f.delete())
LOG.warning("Unable to delete file " + f);
});
for (Path path : FileUtils.listFilesByExtension(removedFile.toPath(), "json")) {
try {
Files.delete(path);
} catch (IOException e) {
LOG.warning("Failed to delete file " + path, e);
}
}
// remove the version from version list regardless of whether the directory was removed successfully or not.
try {
FileUtils.deleteDirectory(removedFile);
FileUtils.deleteDirectory(removedFile.toPath());
} catch (IOException e) {
LOG.warning("Unable to remove version folder: " + file, e);
}
@@ -288,10 +292,10 @@ public class DefaultGameRepository implements GameRepository {
// If user renamed the json file by mistake or created the json file in a wrong name,
// we will find the only json and rename it to correct name.
if (!json.exists()) {
List<File> jsons = FileUtils.listFilesByExtension(dir, "json");
List<Path> jsons = FileUtils.listFilesByExtension(dir.toPath(), "json");
if (jsons.size() == 1) {
LOG.info("Renaming json file " + jsons.get(0) + " to " + json);
if (!jsons.get(0).renameTo(json)) {
if (!jsons.get(0).toFile().renameTo(json)) {
LOG.warning("Cannot rename json file, ignoring version " + id);
return Stream.empty();
}

View File

@@ -378,7 +378,7 @@ public class DefaultLauncher extends Launcher {
public void decompressNatives(File destination) throws NotDecompressingNativesException {
try {
FileUtils.cleanDirectoryQuietly(destination);
FileUtils.cleanDirectoryQuietly(destination.toPath());
for (Library library : version.getLibraries())
if (library.isNative())
new Unzipper(repository.getLibraryFile(version, library), destination)
@@ -596,7 +596,7 @@ public class DefaultLauncher extends Launcher {
if (isUsingLog4j())
extractLog4jConfigurationFile();
String scriptExtension = FileUtils.getExtension(scriptFile);
String scriptExtension = FileUtils.getExtension(scriptFile.getName());
boolean usePowerShell = "ps1".equals(scriptExtension);
if (!usePowerShell) {
@@ -616,8 +616,7 @@ public class DefaultLauncher extends Launcher {
}
}
if (!FileUtils.makeFile(scriptFile))
throw new IOException("Script file: " + scriptFile + " cannot be created.");
Files.createDirectories(scriptFile.toPath().getParent());
try (OutputStream outputStream = Files.newOutputStream(scriptFile.toPath())) {
Charset charset = StandardCharsets.UTF_8;

View File

@@ -63,7 +63,7 @@ public class Datapack {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(datapacks)) {
for (Path datapack : directoryStream) {
if (Files.isDirectory(datapack) && packs.contains(FileUtils.getName(datapack)))
FileUtils.deleteDirectory(datapack.toFile());
FileUtils.deleteDirectory(datapack);
else if (Files.isRegularFile(datapack) && packs.contains(FileUtils.getNameWithoutExtension(datapack)))
Files.delete(datapack);
}
@@ -106,14 +106,14 @@ public class Datapack {
Files.delete(packPng);
}
} else {
FileUtils.copyFile(path.toFile(), datapacks.resolve(FileUtils.getName(path)).toFile());
FileUtils.copyFile(path, datapacks.resolve(FileUtils.getName(path)));
}
}
public void deletePack(Pack pack) throws IOException {
Path subPath = pack.file;
if (Files.isDirectory(subPath))
FileUtils.deleteDirectory(subPath.toFile());
FileUtils.deleteDirectory(subPath);
else if (Files.isRegularFile(subPath))
Files.delete(subPath);

View File

@@ -19,11 +19,9 @@ package org.jackhuang.hmcl.mod;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.DigestUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.Unzipper;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.*;
@@ -63,8 +61,7 @@ public class ModpackInstallTask<T> extends Task<Void> {
@Override
public void execute() throws Exception {
Set<String> entries = new HashSet<>();
if (!FileUtils.makeDirectory(dest))
throw new IOException("Unable to make directory " + dest);
Files.createDirectories(dest.toPath());
HashMap<String, ModpackConfiguration.FileInformation> files = new HashMap<>();
for (ModpackConfiguration.FileInformation file : overrides)

View File

@@ -17,16 +17,19 @@
*/
package org.jackhuang.hmcl.util.io;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.glavo.chardet.DetectedCharset;
import org.glavo.chardet.UniversalDetector;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.ZonedDateTime;
@@ -34,6 +37,7 @@ import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@@ -81,16 +85,12 @@ public final class FileUtils {
return StringUtils.substringBeforeLast(fileName, '.');
}
public static String getNameWithoutExtension(File file) {
return StringUtils.substringBeforeLast(file.getName(), '.');
}
public static String getNameWithoutExtension(Path file) {
return StringUtils.substringBeforeLast(getName(file), '.');
}
public static String getExtension(File file) {
return StringUtils.substringAfterLast(file.getName(), '.');
public static String getExtension(String fileName) {
return StringUtils.substringAfterLast(fileName, '.');
}
public static String getExtension(Path file) {
@@ -105,13 +105,8 @@ public final class FileUtils {
}
public static String getName(Path path) {
if (path.getFileName() == null) return "";
return StringUtils.removeSuffix(path.getFileName().toString(), "/", "\\");
}
public static String getName(Path path, String candidate) {
if (path.getFileName() == null) return candidate;
else return getName(path);
Path fileName = path.getFileName();
return fileName != null ? fileName.toString() : "";
}
// https://learn.microsoft.com/biztalk/core/restrictions-when-configuring-the-file-adapter
@@ -210,21 +205,6 @@ public final class FileUtils {
return new String(bytes, OperatingSystem.NATIVE_CHARSET);
}
/**
* Write plain text to file. Characters are encoded into bytes using UTF-8.
* <p>
* We don't care about platform difference of line separator. Because readText accept all possibilities of line separator.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
* All characters in text will be written into the file in binary format. Existing data will be erased.
*
* @param file the path to the file
* @param text the text being written to file
* @throws IOException if an I/O error occurs
*/
public static void writeText(File file, String text) throws IOException {
writeText(file.toPath(), text);
}
/**
* Write plain text to file. Characters are encoded into bytes using UTF-8.
* <p>
@@ -241,19 +221,6 @@ public final class FileUtils {
Files.writeString(file, text);
}
/**
* Write byte array to file.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
* All bytes in byte array will be written into the file in binary format. Existing data will be erased.
*
* @param file the path to the file
* @param data the data being written to file
* @throws IOException if an I/O error occurs
*/
public static void writeBytes(File file, byte[] data) throws IOException {
writeBytes(file.toPath(), data);
}
/**
* Write byte array to file.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
@@ -278,22 +245,7 @@ public final class FileUtils {
Files.deleteIfExists(directory);
}
public static void deleteDirectory(File directory)
throws IOException {
if (!directory.exists())
return;
if (!isSymlink(directory))
cleanDirectory(directory);
if (!directory.delete()) {
String message = "Unable to delete directory " + directory + ".";
throw new IOException(message);
}
}
public static boolean deleteDirectoryQuietly(File directory) {
public static boolean deleteDirectoryQuietly(Path directory) {
try {
deleteDirectory(directory);
return true;
@@ -315,7 +267,7 @@ public final class FileUtils {
}
public static void copyDirectory(Path src, Path dest, Predicate<String> filePredicate) throws IOException {
Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
Files.walkFileTree(src, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!filePredicate.test(src.relativize(file).toString())) {
@@ -373,9 +325,9 @@ public final class FileUtils {
* @param file the file being moved to trash.
* @return false if moveToTrash does not exist, or platform does not support Desktop.Action.MOVE_TO_TRASH
*/
public static boolean moveToTrash(File file) {
public static boolean moveToTrash(Path file) {
if (OperatingSystem.CURRENT_OS.isLinuxOrBSD() && hasKnownDesktop()) {
if (!file.exists()) {
if (!Files.exists(file)) {
return false;
}
@@ -395,7 +347,7 @@ public final class FileUtils {
Files.createDirectories(infoDir);
Files.createDirectories(filesDir);
String name = file.getName();
String name = getName(file);
Path infoFile = infoDir.resolve(name + ".trashinfo");
Path targetFile = filesDir.resolve(name);
@@ -408,13 +360,13 @@ public final class FileUtils {
}
String time = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ZonedDateTime.now().truncatedTo(ChronoUnit.SECONDS));
if (file.isDirectory()) {
FileUtils.copyDirectory(file.toPath(), targetFile);
if (Files.isDirectory(file)) {
FileUtils.copyDirectory(file, targetFile);
} else {
FileUtils.copyFile(file.toPath(), targetFile);
FileUtils.copyFile(file, targetFile);
}
FileUtils.writeText(infoFile, "[Trash Info]\nPath=" + file.getAbsolutePath() + "\nDeletionDate=" + time + "\n");
FileUtils.writeText(infoFile, "[Trash Info]\nPath=" + file.toAbsolutePath().normalize() + "\nDeletionDate=" + time + "\n");
FileUtils.forceDelete(file);
} catch (IOException e) {
LOG.warning("Failed to move " + file + " to trash", e);
@@ -425,7 +377,7 @@ public final class FileUtils {
}
try {
return java.awt.Desktop.getDesktop().moveToTrash(file);
return java.awt.Desktop.getDesktop().moveToTrash(file.toFile());
} catch (Exception e) {
return false;
}
@@ -460,36 +412,8 @@ public final class FileUtils {
});
}
public static void cleanDirectory(File directory)
throws IOException {
if (!directory.exists()) {
if (!makeDirectory(directory))
throw new IOException("Failed to create directory: " + directory);
return;
}
if (!directory.isDirectory()) {
String message = directory + " is not a directory";
throw new IllegalArgumentException(message);
}
File[] files = directory.listFiles();
if (files == null)
throw new IOException("Failed to list contents of " + directory);
IOException exception = null;
for (File file : files)
try {
forceDelete(file);
} catch (IOException ioe) {
exception = ioe;
}
if (null != exception)
throw exception;
}
public static boolean cleanDirectoryQuietly(File directory) {
@CanIgnoreReturnValue
public static boolean cleanDirectoryQuietly(Path directory) {
try {
cleanDirectory(directory);
return true;
@@ -498,53 +422,12 @@ public final class FileUtils {
}
}
public static void forceDelete(File file)
public static void forceDelete(Path file)
throws IOException {
if (file.isDirectory()) {
if (Files.isDirectory(file))
deleteDirectory(file);
} else {
boolean filePresent = file.exists();
if (!file.delete()) {
if (!filePresent)
throw new FileNotFoundException("File does not exist: " + file);
throw new IOException("Unable to delete file: " + file);
}
}
}
public static boolean isSymlink(File file)
throws IOException {
Objects.requireNonNull(file, "File must not be null");
if (File.separatorChar == '\\')
return false;
File fileInCanonicalDir;
if (file.getParent() == null)
fileInCanonicalDir = file;
else {
File canonicalDir = file.getParentFile().getCanonicalFile();
fileInCanonicalDir = new File(canonicalDir, file.getName());
}
return !fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile());
}
public static void copyFile(File srcFile, File destFile)
throws IOException {
Objects.requireNonNull(srcFile, "Source must not be null");
Objects.requireNonNull(destFile, "Destination must not be null");
if (!srcFile.exists())
throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
if (srcFile.isDirectory())
throw new IOException("Source '" + srcFile + "' exists but is a directory");
if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath()))
throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
File parentFile = destFile.getParentFile();
if (parentFile != null && !FileUtils.makeDirectory(parentFile))
throw new IOException("Destination '" + parentFile + "' directory cannot be created");
if (destFile.exists() && !destFile.canWrite())
throw new IOException("Destination '" + destFile + "' exists but is read-only");
Files.copy(srcFile.toPath(), destFile.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
else
Files.delete(file);
}
public static void copyFile(Path srcFile, Path destFile)
@@ -555,50 +438,20 @@ public final class FileUtils {
throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
if (Files.isDirectory(srcFile))
throw new IOException("Source '" + srcFile + "' exists but is a directory");
Path parentFile = destFile.getParent();
Files.createDirectories(parentFile);
Files.createDirectories(destFile.getParent());
if (Files.exists(destFile) && !Files.isWritable(destFile))
throw new IOException("Destination '" + destFile + "' exists but is read-only");
Files.copy(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
}
public static void moveFile(File srcFile, File destFile) throws IOException {
copyFile(srcFile, destFile);
srcFile.delete();
}
public static boolean makeDirectory(File directory) {
directory.mkdirs();
return directory.isDirectory();
}
public static boolean makeFile(File file) {
return makeDirectory(file.getAbsoluteFile().getParentFile()) && (file.exists() || Lang.test(file::createNewFile));
}
public static List<File> listFilesByExtension(File file, String extension) {
List<File> result = new ArrayList<>();
File[] files = file.listFiles();
if (files != null)
for (File it : files)
if (extension.equals(getExtension(it)))
result.add(it);
return result;
}
/**
* Tests whether the file is convertible to [java.nio.file.Path] or not.
*
* @param file the file to be tested
* @return true if the file is convertible to Path.
*/
public static boolean isValidPath(File file) {
try {
file.toPath();
return true;
} catch (InvalidPathException ignored) {
return false;
public static List<Path> listFilesByExtension(Path file, String extension) {
try (Stream<Path> list = Files.list(file)) {
return list.filter(it -> Files.isRegularFile(it) && extension.equals(getExtension(it)))
.toList();
} catch (IOException e) {
LOG.warning("Failed to list files by extension " + extension, e);
return List.of();
}
}