Java'daki bir dizindeki dosyalar arasında nasıl yineleme yapabilirim?


175

Tüm alt dizinlerdeki dosyalar da dahil olmak üzere bir dizindeki tüm dosyaların bir listesini almam gerekiyor. Java ile dizin yinelemesini gerçekleştirmenin standart yolu nedir?

Yanıtlar:


207

File#isDirectory()Verilen dosyanın (yol) bir dizin olup olmadığını test etmek için kullanabilirsiniz . Eğer trueöyleyse, o zaman File#listFiles()sonucu ile aynı yöntemi tekrar çağırırsınız . Buna özyineleme denir .

İşte temel bir başlama örneği.

public static void main(String... args) {
    File[] files = new File("C:/").listFiles();
    showFiles(files);
}

public static void showFiles(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            System.out.println("Directory: " + file.getName());
            showFiles(file.listFiles()); // Calls same method again.
        } else {
            System.out.println("File: " + file.getName());
        }
    }
}

Bunun, StackOverflowErrorağaç JVM'nin yığınının tutabileceğinden daha derin olduğunda hassas olduğunu unutmayın . Bunun yerine yinelemeli bir yaklaşım veya kuyruk özyineleme kullanmak isteyebilirsiniz , ancak bu başka bir konudur;)


teşekkürler Balus, bunun genel bir tahmin olarak ne kadar derin olabileceği hakkında bir fikrin var mı?
James

10
JVM'nizin bellek ayarlarına bağlıdır. Ama genellikle birkaç bin gibi bir şey. Eğer böyle bir dizine rastlayabileceğinizi düşünüyorsanız, özyineleme kullanmayın.
Mike Baranczak

4
Bu, NullPointerExceptiondosya sistemi çağrı arasında değiştiğinde isDirectoryve bloklar veya gerçekten şanssız olursanız listFilesolabileceği gibi bir zamana karşı hassastır System.out.println. Çıktının listFilesboş olup olmadığını kontrol etmek o yarış koşulunu çözecektir.
Mike Samuel

1
@BoratSagdiyev, Eski Java dosya API'lerini kullanmıyorsanız, ancak modern bir JVM kullanıyorsanız, java.nio.file.DirectoryStreambir dizin üzerinde yinelenmenize izin verir ve küçük bir bellek ayak izine sahip olmak için uygulanabilir, ancak kesin olarak söylemenin tek yolu belirli bir platformda bellek kullanımını izlemek için.
Mike Samuel

1
"C: \\" klasörü bir örneğin en iyi tercihi değildir)
Vyacheslav

86

Java 1.7 kullanıyorsanız, java.nio.file.Files.walkFileTree(...) .

Örneğin:

public class WalkFileTreeExample {

  public static void main(String[] args) {
    Path p = Paths.get("/usr");
    FileVisitor<Path> fv = new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
        System.out.println(file);
        return FileVisitResult.CONTINUE;
      }
    };

    try {
      Files.walkFileTree(p, fv);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

Java 8 kullanıyorsanız akış arayüzünü aşağıdakilerle birlikte kullanabilirsiniz java.nio.file.Files.walk(...):

public class WalkFileTreeExample {

  public static void main(String[] args) {
    try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) {
      paths.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

1
dizinler yürüdüğünde bir kontrol noktası koymak ve bir işlevi yürütmek için akarsu bir yolu var mı?
Raghu DV

28

Check out FileUtils Apache Commons sınıfı - özellikle iterateFiles :

Belirli bir dizindeki (ve isteğe bağlı olarak alt dizinlerindeki) dosyalar üzerinde yinelemeye izin verir.


5
Bu API gerçekten akış gerçekleştirmiyor (mem kullanımını önemsiyorsanız), önce bir koleksiyon oluşturur, ancak daha sonra bunun üzerinde bir yineleyici döndürür: return listFiles (directory, fileFilter, dirFilter) .iterator ();
Gili Nachum

Java 1.6 için iyi bir seçenek.
David

@GiliNachum ile aynı fikirde. Apache tarafından FileUtils önce tüm dosyaları toplar ve onlar için bir yineleyici verir. Çok sayıda dosyanız varsa kaynaklar için zararlıdır.
Bogdan Samondros

8

Java 7+ için ayrıca https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html var

Javadoc'tan alınan örnek:

List<Path> listSourceFiles(Path dir) throws IOException {
   List<Path> result = new ArrayList<>();
   try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
       for (Path entry: stream) {
           result.add(entry);
       }
   } catch (DirectoryIteratorException ex) {
       // I/O error encounted during the iteration, the cause is an IOException
       throw ex.getCause();
   }
   return result;
}

8

kullanma org.apache.commons.io.FileUtils

File file = new File("F:/Lines");       
Collection<File> files = FileUtils.listFiles(file, null, true);     
for(File file2 : files){
    System.out.println(file2.getName());            
} 

Alt dizinlerden dosya istemiyorsanız false kullanın.


3

Bu bir ağaç, özyineleme arkadaşın: üst dizinden başla ve bir dizi alt Dosya alma yöntemini çağır. Alt dizi üzerinden yineleme yapın. Geçerli değer bir dizinse, yöntemi yönteminizin özyinelemeli çağrısına iletin. Değilse, yaprak dosyasını uygun şekilde işleyin.


2

Belirtildiği gibi, bu bir özyineleme problemidir. Özellikle,

listFiles() 

Java Dosya API olarak burada . Bir dizindeki tüm dosyaların bir dizisini döndürür. İle birlikte kullanma

isDirectory()

daha fazla bilgi almanız gerekip gerekmediğini görmek iyi bir başlangıçtır.


Yanıttaki bağlantı koptuğundan bu bağlantı yararlı olabilir.
Donglecow

0

@Msandiford yanıtı ile eklemek için, çoğu zaman bir dosya ağacının yürüdüğü zaman, bir işlevi bir dizin olarak yürütmek veya belirli bir dosya ziyaret etmek isteyebilirsiniz. Eğer u akışları kullanmak konusunda isteksizseniz. Geçersiz kılınan aşağıdaki yöntemler uygulanabilir

Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
    new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException {
                // Do someting before directory visit
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException {
                // Do something when a file is visited
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                throws IOException {
                // Do Something after directory visit 
                return FileVisitResult.CONTINUE;
        }
});

0

Ayrıca, dosya geçişi için File.list'i (Dosyaadı Filtresi) (ve varyantlarını) kötüye kullanabilirsiniz. Kısa kod ve erken java sürümlerinde çalışır, örneğin:

// list files in dir
new File(dir).list(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        String file = dir.getAbsolutePath() + File.separator + name;
        System.out.println(file);
        return false;
    }
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.