سؤال

هل هناك طريقة لحذف الدلائل بأكملها بشكل متكرر في جافا؟

في الحالة العادية، من الممكن حذف دليل فارغ. ومع ذلك، عندما يتعلق الأمر بحذف الدلائل بأكملها مع المحتويات، فإنه ليس بهذه البساطة بعد الآن.

كيف يمكنك حذف الدلائل بأكملها مع محتويات في Java؟

هل كانت مفيدة؟

المحلول

يجب عليك التحقق من المشاع apache-io. وبعد لديها أ fileutils. الطبقة التي ستفعل ما تريد.

FileUtils.deleteDirectory(new File("directory"));

نصائح أخرى

مع جافا 7، يمكننا في النهاية قم بذلك مع كشف Symlink موثوق. (أنا لا أفكر في كومونات Apache - IO موثوق بها اكتشاف Symlink في هذا الوقت، لأنه لا يتعامل مع الروابط على Windows تم إنشاؤه mklink.)

من أجل التاريخ، إليك إجابة ما قبل جافا 7، والتي يتبع symlinks.

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}

في Java 7+ يمكنك استخدام Files صف دراسي. الرمز بسيط جدا:

Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       Files.delete(file);
       return FileVisitResult.CONTINUE;
   }

   @Override
   public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
       Files.delete(dir);
       return FileVisitResult.CONTINUE;
   }
});

وأضاف Java 7 دعم أدلة المشي مع التعامل مع Symlink:

import java.nio.file.*;

public static void removeRecursive(Path path) throws IOException
{
    Files.walkFileTree(path, new SimpleFileVisitor<Path>()
    {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
        {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
        {
            // try to delete the file anyway, even if its attributes
            // could not be read, since delete-only access is
            // theoretically possible
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
        {
            if (exc == null)
            {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
            else
            {
                // directory iteration failed; propagate exception
                throw exc;
            }
        }
    });
}

يمكنني استخدام هذا كعطلة من الأساليب الخاصة بالمنصة (في هذا غير مختبر الشفرة):

public static void removeDirectory(Path directory) throws IOException
{
    // does nothing if non-existent
    if (Files.exists(directory))
    {
        try
        {
            // prefer OS-dependent directory removal tool
            if (SystemUtils.IS_OS_WINDOWS)
                Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
            else if (SystemUtils.IS_OS_UNIX)
                Processes.execute("/bin/rm", "-rf", directory.toString());
        }
        catch (ProcessExecutionException | InterruptedException e)
        {
            // fallback to internal implementation on error
        }

        if (Files.exists(directory))
            removeRecursive(directory);
    }
}

(SystemUtils من اباتشي المشاع Lang.. وبعد العمليات خاصة ولكن يجب أن يكون سلوكه واضحا.)

حل واحد بطانة (Java8) لحذف جميع الملفات والدلائل بشكل متكرر بما في ذلك دليل البداية:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

نحن نستخدم مقارنة للنظام العكسي، وإلا فلن تتمكن FILE :: DELETE من حذف الدليل غير الفارغ المحتمل. لذلك، إذا كنت ترغب في الحفاظ على الدلائل وحذف الملفات فقط فقط قم بإزالة المقارنة في فرزها () أو قم بإزالة الفرز بالكامل وإضافة مرشح الملفات:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

رأى فقط الحل الخاص بي هو نفسه أكثر أو أقل مثل Erickson، تعبئتها فقط كطريقة ثابتة. إسقاط هذا في مكان ما، إنه وزن أخف بكثير من تثبيت كل مشوكون Apache لشيء (كما ترون) بسيط للغاية.

public class FileUtils {
    /**
     * By default File#delete fails for non-empty directories, it works like "rm". 
     * We need something a little more brutual - this does the equivalent of "rm -r"
     * @param path Root File Path
     * @return true iff the file and all sub files/directories have been removed
     * @throws FileNotFoundException
     */
    public static boolean deleteRecursive(File path) throws FileNotFoundException{
        if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
        boolean ret = true;
        if (path.isDirectory()){
            for (File f : path.listFiles()){
                ret = ret && deleteRecursive(f);
            }
        }
        return ret && path.delete();
    }
}

حل مع كومة ودون أساليب متكررة:

File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
    if (stack.lastElement().isDirectory()) {
        currList = stack.lastElement().listFiles();
        if (currList.length > 0) {
            for (File curr: currList) {
                stack.push(curr);
            }
        } else {
            stack.pop().delete();
        }
    } else {
        stack.pop().delete();
    }
}

جوجا ملك Files.deleteRecursively(File) مدعومة حتى الجوافة 9..

من عند الجوافة 10.:

إهمال. تعاني هذه الطريقة من سوء اكتشاف الرياح وظروف السباق. يمكن دعم هذه الوظيفة بشكل مناسب فقط عن طريق القصف إلى أمر نظام التشغيل مثل rm -rf أو del /s. من المقرر إزالة هذه الطريقة من Guava في Guava Release 11.0.

لذلك، لا توجد طريقة من هذا القبيل في الجوافة 11..

إذا كان لديك الربيع، يمكنك استخدام filesystemutils.dleterEnsively.:

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

أو إذا كنت ترغب في التعامل مع IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
public void deleteRecursive(File path){
    File[] c = path.listFiles();
    System.out.println("Cleaning out folder:" + path.toString());
    for (File file : c){
        if (file.isDirectory()){
            System.out.println("Deleting file:" + file.toString());
            deleteRecursive(file);
            file.delete();
        } else {
            file.delete();
        }
    }
    path.delete();
}
static public void deleteDirectory(File path) 
{
    if (path == null)
        return;
    if (path.exists())
    {
        for(File f : path.listFiles())
        {
            if(f.isDirectory()) 
            {
                deleteDirectory(f);
                f.delete();
            }
            else
            {
                f.delete();
            }
        }
        path.delete();
    }
}

طريقتان للفشل مع Symlinks والرمز أعلاه ... ولا أعرف الحل.

الطريق # 1.

قم بتشغيل هذا لإنشاء اختبار:

echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete

هنا ترى ملف الاختبار الخاص بك واختبار دليل الاختبار:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

ثم قم بتشغيل Commons-io Deletedirectory (). تعطل قوله لم يتم العثور على الملف. لست متأكدا ما تفعله الأمثلة الأخرى هنا. سيحذف الأمر Linux RM ببساطة الرابط، وسيقوم RM -R على الدليل أيضا.

Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

الطريق # 2

قم بتشغيل هذا لإنشاء اختبار:

mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete

هنا ترى ملف الاختبار الخاص بك واختبار دليل الاختبار:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

ثم قم بتشغيل Commons-io deletedirectory () أو رمز المثال المنشور. إنه يحذف الدليل ليس فقط، ولكن يتم حذف TestFile الخاص بك خارج الدليل. (dereferences الدليل ضمنيا، وحذف المحتويات). RM -R ستحذف الرابط فقط. تحتاج إلى استخدام شيء من هذا القبيل حذف الملفات غير المنفجرة: "Find -L Dirtodelete -Type F -EXEC RM {} ؛".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:

يمكنك استخدام:

org.apache.commons.io.FileUtils.deleteQuietly(destFile);

يحذف ملف، أبدا رمي استثناء. إذا كان الملف دليل، حذفه وجميع الدلائل الفرعية. الفرق بين file.delete () وهذه الطريقة هي: لا يجب أن يكون دليل حذف فارغا. يتم إلقاء أي استثناءات عند عدم حذف ملف أو دليل.

الحل الأمثل الذي يتعامل مع استثناء باستمرار مع النهج الذي يجب أن يصف الاستثناء الذي ألقيته من الأسلوب دائما ما تحاول هذه الطريقة (وفشل) القيام به:

private void deleteRecursive(File f) throws Exception {
    try {
        if (f.isDirectory()) {
            for (File c : f.listFiles()) {
                deleteRecursive(c);
            }
        }
        if (!f.delete()) {
            throw new Exception("Delete command returned false for file: " + f);
        }
    } 
    catch (Exception e) {
        throw new Exception("Failed to delete the folder: " + f, e);
    }
}

في المشاريع القديمة، أحتاج إلى إنشاء رمز Java الأصلي. أقوم بإنشاء هذا الرمز يشبه رمز Paulitex. أنظر لهذا:

public class FileHelper {

   public static boolean delete(File fileOrFolder) {
      boolean result = true;
      if(fileOrFolder.isDirectory()) {
         for (File file : fileOrFolder.listFiles()) {
            result = result && delete(file);
         }
      }
      result = result && fileOrFolder.delete();
      return result;
   } 
}

واختبار الوحدة:

public class FileHelperTest {

    @Before
    public void setup() throws IOException {
       new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
    }

    @Test
    public void deleteFolderWithFiles() {
       File folderToDelete = new File("FOLDER_TO_DELETE");
       Assert.assertTrue(FileHelper.delete(folderToDelete));
       Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
    }

}

فيما يلي طريقة عارية هي الطريقة الرئيسية التي تقبل حجة سطر الأوامر، قد تحتاج إلى إلحاق التحقق من الأخطاء الخاصة بك أو قالبها إلى كيفية ترى مناسبا.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class DeleteFiles {

/**
 * @param intitial arguments take in a source to read from and a 
 * destination to read to
 */
    public static void main(String[] args)
                     throws FileNotFoundException,IOException {
        File src = new File(args[0]);
        if (!src.exists() ) {
            System.out.println("FAILURE!");
        }else{
            // Gathers files in directory
            File[] a = src.listFiles();
            for (int i = 0; i < a.length; i++) {
                //Sends files to recursive deletion method
                fileDelete(a[i]);
            }
            // Deletes original source folder
            src.delete();
            System.out.println("Success!");
        }
    }

    /**
     * @param srcFile Source file to examine
     * @throws FileNotFoundException if File not found
     * @throws IOException if File not found
     */
    private static void fileDelete(File srcFile)
                     throws FileNotFoundException, IOException {
        // Checks if file is a directory
        if (srcFile.isDirectory()) {
            //Gathers files in directory
            File[] b = srcFile.listFiles();
            for (int i = 0; i < b.length; i++) {
                //Recursively deletes all files and sub-directories
                fileDelete(b[i]);
            }
            // Deletes original sub-directory file
            srcFile.delete();
        } else {
            srcFile.delete();
        }
    }
}

أتمنى أن يساعد ذلك!

أدناه رمز حذف جميع المحتويات بشكل متكرر في مجلد معين.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}

ربما قد يكون الحل لهذا المشكلة هو إعادة تشغيل طريقة حذف فئة الملفات باستخدام الرمز من إجابة Erickson:

public class MyFile extends File {

  ... <- copy constructor

  public boolean delete() {
    if (f.isDirectory()) {
      for (File c : f.listFiles()) {
        return new MyFile(c).delete();
      }
    } else {
        return f.delete();
    }
  }
}

بدون المشاع IO و <Java SE 7

public static void deleteRecursive(File path){
            path.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if (pathname.isDirectory()) {
                        pathname.listFiles(this);
                        pathname.delete();
                    } else {
                        pathname.delete();
                    }
                    return false;
                }
            });
            path.delete();
        }

في حين أن الملفات يمكن حذفها بسهولة باستخدام file.delete ()، فإن الدلائل مطلوبة لتكون فارغة ليتم حذفها. استخدم العودية للقيام بذلك بسهولة. علي سبيل المثال:

public static void clearFolders(String[] args) {
        for(String st : args){
            File folder = new File(st);
            if (folder.isDirectory()) {
                File[] files = folder.listFiles();
                if(files!=null) { 
                    for(File f: files) {
                        if (f.isDirectory()){
                            clearFolders(new String[]{f.getAbsolutePath()});
                            f.delete();
                        } else {
                            f.delete();
                        }
                    }
                }
            }
        }
    }

ترميز هذا الروتين الذي يحتوي على 3 معايير أمان للاستخدام الأكثر أمانا.

package ch.ethz.idsc.queuey.util;

import java.io.File;
import java.io.IOException;

/** recursive file/directory deletion
 * 
 * safety from erroneous use is enhanced by three criteria
 * 1) checking the depth of the directory tree T to be deleted
 * against a permitted upper bound "max_depth"
 * 2) checking the number of files to be deleted #F
 * against a permitted upper bound "max_count"
 * 3) if deletion of a file or directory fails, the process aborts */
public final class FileDelete {
    /** Example: The command
     * FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
     * deletes given directory with sub directories of depth of at most 2,
     * and max number of total files less than 1000. No files are deleted
     * if directory tree exceeds 2, or total of files exceed 1000.
     * 
     * abort criteria are described at top of class
     * 
     * @param file
     * @param max_depth
     * @param max_count
     * @return
     * @throws Exception if criteria are not met */
    public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
        return new FileDelete(file, max_depth, max_count);
    }

    // ---
    private final File root;
    private final int max_depth;
    private int removed = 0;

    /** @param root file or a directory. If root is a file, the file will be deleted.
     *            If root is a directory, the directory tree will be deleted.
     * @param max_depth of directory visitor
     * @param max_count of files to delete
     * @throws IOException */
    private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
        this.root = root;
        this.max_depth = max_depth;
        // ---
        final int count = visitRecursively(root, 0, false);
        if (count <= max_count) // abort criteria 2)
            visitRecursively(root, 0, true);
        else
            throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
    }

    private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
        if (max_depth < depth) // enforce depth limit, abort criteria 1)
            throw new IOException("directory tree exceeds permitted depth");
        // ---
        int count = 0;
        if (file.isDirectory()) // if file is a directory, recur
            for (File entry : file.listFiles())
                count += visitRecursively(entry, depth + 1, delete);
        ++count; // count file as visited
        if (delete) {
            final boolean deleted = file.delete();
            if (!deleted) // abort criteria 3)
                throw new IOException("cannot delete " + file.getAbsolutePath());
            ++removed;
        }
        return count;
    }

    public int deletedCount() {
        return removed;
    }

    public void printNotification() {
        int count = deletedCount();
        if (0 < count)
            System.out.println("deleted " + count + " file(s) in " + root);
    }
}

حسنا، دعنا نفترض مثالا،

import java.io.File;
import java.io.IOException;

public class DeleteDirectory
{
   private static final String folder = "D:/project/java";

   public static void main(String[] args) throws IOException
   {
      File fl = new File(folder);
      if(!fl.exists()) // checking if directory exists
      {
         System.out.println("Sorry!! directory doesn't exist.");
      }
      else
      {
         DeleteDirectory dd = new DeleteDirectory();
         dd.deleteDirectory(fl);
      }
   }

   public void deleteDirectory(File file) throws IOException
   {
      if(file.isDirectory())
      {
         if(file.list().length == 0)
         { 
            deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
         }
         else
         {
            File fe[] = file.listFiles();
            for(File deleteFile : fe)
            {
               deleteDirectory(deleteFile); // recursive call
            }
            if(file.list().length == 0)
            {
               deleteEmptyDirectory(file);
            }
         }
      }
      else
      {
         file.delete();
         System.out.println("File deleted : " + file.getAbsolutePath());
      }
   }

   private void deleteEmptyDirectory(File fi)
   {
      fi.delete();
      System.out.println("Directory deleted : " + fi.getAbsolutePath());
   }
}

لمزيد من المعلومات، يرجى الإشارة إلى الموارد

حذف الدليل

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top