Java, lista apenas subdiretórios de um diretório, não arquivos

100

Em Java, como listo apenas os subdiretórios de um diretório?

Eu gostaria de usar a funcionalidade java.io.File, qual é o melhor método em Java para fazer isso?

Lokesh Paunikar
fonte

Respostas:

141

Você pode usar a classe File para listar os diretórios.

File file = new File("/path/to/directory");
String[] directories = file.list(new FilenameFilter() {
  @Override
  public boolean accept(File current, String name) {
    return new File(current, name).isDirectory();
  }
});
System.out.println(Arrays.toString(directories));

Atualizar

O comentário do autor neste post queria uma maneira mais rápida, ótima discussão aqui: Como recuperar uma lista de diretórios RAPIDAMENTE em Java?

Basicamente:

  1. Se você controlar a estrutura do arquivo, eu tentaria evitar entrar nessa situação.
  2. No Java NIO.2, você pode usar a função de diretórios para retornar um iterador para permitir maior escala. A classe de fluxo de diretório é um objeto que você pode usar para iterar as entradas em um diretório.
Mohamed Mansour
fonte
oi, obrigado pela resposta. Mas não preciso iterar todos os itens de um diretório. Tenho que listar diretamente o subdiretório do diretório. B'coz Tenho muitos arquivos e apenas alguns subdiretórios em um diretório, portanto, verificar o isDirectory () é demorado. por favor me responda de outra maneira.
Lokesh Paunikar
Eu atualizei meu post, em particular, dê uma olhada no comentário de Jon Skeet sobre a questão. E a resposta NIO desde Java NIO 2 tem um iterador para a função de diretórios que retorna um fluxo de diretórios.
Mohamed Mansour
A que comentário Skeet você está se referindo? Qual é a resposta de melhor desempenho aqui?
Stealth Rabino
107

Uma solução Java 8 muito simples:

File[] directories = new File("/your/path/").listFiles(File::isDirectory);

É equivalente a usar um FileFilter (funciona com Java mais antigo também):

File[] directories = new File("/your/path/").listFiles(new FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.isDirectory();
    }
});
headsvk
fonte
4
Como os dois pontos duplos ::funcionam neste caso?
snickers10m
Percebi que nenhuma outra resposta usa FileFilter, então adicionei a versão equivalente sem usar referências de método. Para obter mais informações sobre referências de método, consulte esta pergunta do SO ou este artigo .
headsvk
isto obtém subdiretórios ou apenas os diretórios diretamente em / seu / caminho /?
amadain
@amadain sem recursão conforme esperado docs.oracle.com/javase/7/docs/api/java/io/File.html#listFiles ()
headsvk
14

@Mohamed Mansour você estava quase lá ... o argumento "dir" que você estava usando é na verdade o caminho atual, então ele sempre retornará verdadeiro. Para ver se a criança é um subdiretório ou não, você precisa testar essa criança.

File file = new File("/path/to/directory");
String[] directories = file.list(new FilenameFilter() {
  @Override
  public boolean accept(File current, String name) {
    return new File(current, name).isDirectory();
  }
});
System.out.println(Arrays.toString(directories));
Javier Buzzi
fonte
7

Caso você esteja interessado em uma solução usando Java 7 e NIO.2, poderia ser assim:

private static class DirectoriesFilter implements Filter<Path> {
    @Override
    public boolean accept(Path entry) throws IOException {
        return Files.isDirectory(entry);
    }
}

try (DirectoryStream<Path> ds = Files.newDirectoryStream(FileSystems.getDefault().getPath(root), new DirectoriesFilter())) {
        for (Path p : ds) {
            System.out.println(p.getFileName());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
voo
fonte
3
ArrayList<File> directories = new ArrayList<File>(
    Arrays.asList(
        new File("your/path/").listFiles(File::isDirectory)
    )
);
bcangas97
fonte
Olá, bem-vindo ao StackOverflow! Você pode elaborar sua resposta um pouco? Gosta de explicar partes interessantes de seus trechos de código ou criar um link para a documentação para leitura futura?
Richard-Degenne de
Esta deve ser a resposta correta, pois fornece um objeto Arquivo com o Caminho Canônico completo. Isso pode ser antigo, mas vale a pena ressaltar
Jero Dungog
2

Para os interessados ​​também em Java 7 e NIO, existe uma solução alternativa para a resposta de @voo acima . Podemos usar um try-with-resources que chama Files.find()e uma função lambda que é usada para filtrar os diretórios.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;


final Path directory = Paths.get("/path/to/folder");

try (Stream<Path> paths = Files.find(directory, Integer.MAX_VALUE, (path, attributes) -> attributes.isDirectory())) {
    paths.forEach(System.out::println);
} catch (IOException e) {
    ...
}

Podemos até filtrar diretórios por nome, alterando a função lambda:

(path, attributes) -> attributes.isDirectory() && path.toString().contains("test")

ou por data:

final long now = System.currentTimeMillis();
final long yesterday = new Date(now - 24 * 60 * 60 * 1000L).getTime();

// modified in the last 24 hours
(path, attributes) -> attributes.isDirectory() && attributes.lastModifiedTime().toMillis() > yesterday
Hugo Teixeira
fonte
2

Eu gostaria de usar a funcionalidade java.io.File,

Em 2012 (data da pergunta) sim, hoje não. java.nioA API deve ser favorecida para tais requisitos.

Terrível com tantas respostas, mas não da maneira simples que eu usaria Files.walk().filter().collect().

Globalmente, duas abordagens são possíveis:

1) Files.walk(Path start, )não tem maxDepthlimitações enquanto

2) Files.walk(Path start, int maxDepth, FileVisitOption... options)permite configurá-lo.

Sem especificar qualquer limitação de profundidade, daria:

Path directory = Paths.get("/foo/bar");

try {
    List<Path> directories =
            Files.walk(directory)
                 .filter(Files::isDirectory)
                 .collect(Collectors.toList());
} catch (IOException e) {
    // process exception
}

E se por razões de legado, você precisa obter uma lista, Filevocê pode simplesmente adicionar uma map(Path::toFile)operação antes da coleta:

Path directory = Paths.get("/foo/bar");

try {
    List<File> directories =
            Files.walk(directory)
                 .filter(Files::isDirectory)
                 .map(Path::toFile)
                 .collect(Collectors.toList());
} catch (IOException e) {
    // process exception
}
davidxxx
fonte
Também existe o Files.list(Path)que é provavelmente o mesmo que Files.walk(Path,1).
David L.
@David L De fato, Files.list(Path)é uma alternativa justa se não quisermos iterar pastas recursivamente. Para iterar pastas recursivamente, walk()ajusta-se melhor.
davidxxx
1

A solução que funcionou para mim está faltando na lista de respostas. Portanto, estou postando esta solução aqui:

File[]dirs = new File("/mypath/mydir/").listFiles((FileFilter)FileFilterUtils.directoryFileFilter());

Aqui, usei org.apache.commons.io.filefilter.FileFilterUtilsdo Apache commons-io-2.2.jar. Sua documentação está disponível aqui: https://commons.apache.org/proper/commons-io/javadocs/api-2.2/org/apache/commons/io/filefilter/FileFilterUtils.html

Abhishek Oza
fonte
0

Dado um diretório inicial como um String

  1. Crie um método que tenha um Stringcaminho como parâmetro. No método:
  2. Crie um novo objeto File com base no diretório inicial
  3. Obtenha uma série de arquivos no diretório atual usando o listFilesmétodo
  4. Percorrer a matriz de arquivos
    1. Se for um arquivo, continue o loop
    2. Se for um diretório, imprima o nome e recurse neste novo caminho de diretório
Jonathon Faust
fonte
oi, obrigado pela resposta. Mas não preciso iterar todos os itens de um diretório. Tenho que listar diretamente o subdiretório do diretório. B'coz Tenho muitos arquivos e apenas alguns subdiretórios em um diretório, portanto, verificar o isDirectory () é demorado. por favor me responda de outra maneira.
Lokesh Paunikar
0

Aqui está a solução para o meu código. Acabei de fazer uma pequena mudança desde a primeira resposta . Isso listará todas as pastas apenas no diretório desejado, linha por linha:

try {
            File file = new File("D:\\admir\\MyBookLibrary");
            String[] directories = file.list(new FilenameFilter() {
              @Override
              public boolean accept(File current, String name) {
                return new File(current, name).isDirectory();
              }
            });
            for(int i = 0;i < directories.length;i++) {
                if(directories[i] != null) {
                    System.out.println(Arrays.asList(directories[i]));

                }
            }
        }catch(Exception e) {
            System.err.println("Error!");
        }
Tabby Auguste
fonte