mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
use NIO when available for recursive file deletion
This commit is contained in:
@@ -24,6 +24,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
@@ -66,6 +70,81 @@ public class FileUtilRt {
|
||||
|
||||
private static String ourCanonicalTempPathCache = null;
|
||||
|
||||
protected static final boolean NIO_FILE_API_AVAILABLE;
|
||||
|
||||
// todo: replace reflection with normal code after migration to JDK 1.8
|
||||
private static Method ourFilesDeleteIfExistsMethod;
|
||||
private static Method ourFilesWalkMethod;
|
||||
private static Method ourFileToPathMethod;
|
||||
private static Object ourDeletionVisitor;
|
||||
static {
|
||||
boolean initSuccess = false;
|
||||
try {
|
||||
final Class<?> pathClass = Class.forName("java.nio.file.Path");
|
||||
final Class<?> visitorClass = Class.forName("java.nio.file.FileVisitor");
|
||||
final Class<?> filesClass = Class.forName("java.nio.file.Files");
|
||||
|
||||
ourFileToPathMethod = Class.forName("java.io.File").getMethod("toPath");
|
||||
ourFilesWalkMethod = filesClass.getMethod("walkFileTree", pathClass, visitorClass);
|
||||
ourFilesDeleteIfExistsMethod = filesClass.getMethod("deleteIfExists", pathClass);
|
||||
final Class<?> fileVisitResultClass = Class.forName("java.nio.file.FileVisitResult");
|
||||
final Object Result_Continue = fileVisitResultClass.getDeclaredField("CONTINUE").get(null);
|
||||
final Object Result_Terminate = fileVisitResultClass.getDeclaredField("TERMINATE").get(null);
|
||||
ourDeletionVisitor = Proxy.newProxyInstance(FileUtilRt.class.getClassLoader(), new Class[]{visitorClass}, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (args.length == 2) {
|
||||
final Object second = args[1];
|
||||
if (second instanceof Throwable) {
|
||||
throw (Throwable)second;
|
||||
}
|
||||
final String methodName = method.getName();
|
||||
if ("visitFile".equals(methodName) || "postVisitDirectory".equals(methodName)) {
|
||||
if (!performDelete(args[0])) {
|
||||
return Result_Terminate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result_Continue;
|
||||
}
|
||||
|
||||
private boolean performDelete(@NotNull final Object fileObject) {
|
||||
Boolean result = doIOOperation(new RepeatableIOOperation<Boolean, RuntimeException>() {
|
||||
public Boolean execute(boolean lastAttempt) {
|
||||
try {
|
||||
//Files.deleteIfExists(file);
|
||||
ourFilesDeleteIfExistsMethod.invoke(null, fileObject);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
if (!(e.getCause() instanceof IOException)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
return lastAttempt? Boolean.FALSE : null;
|
||||
}
|
||||
});
|
||||
return Boolean.TRUE.equals(result);
|
||||
}
|
||||
|
||||
});
|
||||
initSuccess = true;
|
||||
LOG.info("Using NIO-based file deletion");
|
||||
}
|
||||
catch (Throwable ignored) {
|
||||
LOG.info("Was not able to detect NIO API");
|
||||
ourFileToPathMethod = null;
|
||||
ourFilesWalkMethod = null;
|
||||
ourFilesDeleteIfExistsMethod = null;
|
||||
ourDeletionVisitor = null;
|
||||
}
|
||||
NIO_FILE_API_AVAILABLE = initSuccess;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static String getExtension(@NotNull String fileName) {
|
||||
int index = fileName.lastIndexOf('.');
|
||||
@@ -538,10 +617,44 @@ public class FileUtilRt {
|
||||
* @return true if the file did not exist or was successfully deleted
|
||||
*/
|
||||
public static boolean delete(@NotNull File file) {
|
||||
if (NIO_FILE_API_AVAILABLE) {
|
||||
return deleteRecursivelyNIO(file);
|
||||
}
|
||||
return deleteRecursively(file);
|
||||
}
|
||||
|
||||
protected static boolean deleteRecursivelyNIO(File file) {
|
||||
try {
|
||||
/*
|
||||
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.deleteIfExists(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.deleteIfExists(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
*/
|
||||
final Object pathObject = ourFileToPathMethod.invoke(file);
|
||||
ourFilesWalkMethod.invoke(null, pathObject, ourDeletionVisitor);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean deleteRecursively(@NotNull File file) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File child : files) {
|
||||
if (!delete(child)) return false;
|
||||
if (!deleteRecursively(child)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -421,6 +421,13 @@ public class FileUtil extends FileUtilRt {
|
||||
}
|
||||
|
||||
public static boolean delete(@NotNull File file) {
|
||||
if (NIO_FILE_API_AVAILABLE) {
|
||||
return deleteRecursivelyNIO(file);
|
||||
}
|
||||
return deleteRecursively(file);
|
||||
}
|
||||
|
||||
private static boolean deleteRecursively(@NotNull File file) {
|
||||
FileAttributes attributes = FileSystemUtil.getAttributes(file);
|
||||
if (attributes == null) return true;
|
||||
|
||||
@@ -428,7 +435,7 @@ public class FileUtil extends FileUtilRt {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File child : files) {
|
||||
if (!delete(child)) return false;
|
||||
if (!deleteRecursively(child)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user