Um guia para NIO2 FileVisitor

Um guia para NIO2 FileVisitor

1. Visão geral

Neste artigo, vamos explorar um recurso interessante do NIO2 - a interfaceFileVisitor.

Todos os sistemas operacionais e vários aplicativos de terceiros têm uma função de pesquisa de arquivos em que um usuário define os critérios de pesquisa.

Essa interface é o que precisamos para implementar essa funcionalidade em um aplicativo Java. Se você precisar pesquisar todos os arquivos.mp3, encontrar e excluir.class arquivos ou encontrar todos os arquivos que não foram acessados ​​no último mês, então esta interface é o que você precisa.

Todas as classes necessárias para implementar essa funcionalidade estão agrupadas em um pacote:

import java.nio.file.*;

2. ComoFileVisitor funciona

Com a interfaceFileVisitor, você pode percorrer a árvore de arquivos em qualquer profundidade e executar qualquer ação nos arquivos ou diretórios encontrados em qualquer ramificação.

Uma implementação típica da interfaceFileVisitor se parece com isto:

public class FileVisitorImpl implements FileVisitor {

    @Override
    public FileVisitResult preVisitDirectory(
      Path dir, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFile(
      Path file, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFileFailed(
      Path file, IOException exc) {
        return null;
    }

    @Override
    public FileVisitResult postVisitDirectory(
      Path dir, IOException exc) {
        return null;
    }
}

Os quatro métodos de interface nos permitem especificar o comportamento necessário em pontos-chave do processo de travessia: antes de um diretório ser acessado, quando um arquivo é visitado ou quando ocorre uma falha e depois que um diretório é acessado, respectivamente.

O valor de retorno em cada estágio é do tipoFileVisitResulte controla o fluxo da travessia. Talvez você queira percorrer a árvore de arquivos procurando um diretório específico e finalizar o processo quando ele for encontrado, ou desejar pular diretórios ou arquivos específicos.

FileVisitResult é um enum de quatro valores de retorno possíveis para os métodos de interfaceFileVisitor:

  • FileVisitResult.CONTINUE - indica que a travessia da árvore de arquivos deve continuar após o método que o retorna sair

  • FileVisitResult.TERMINATE - interrompe a travessia da árvore de arquivos e nenhum diretório ou arquivo adicional é visitado

  • FileVisitResult.SKIP_SUBTREE - este resultado só é significativo quando retornado da APIpreVisitDirectory; em outro lugar, funciona comoCONTINUE. Indica que o diretório atual e todos os seus subdiretórios devem ser ignorados

  • FileVisitResult.SKIP_SIBLINGS - indica que a travessia deve continuar sem visitar os irmãos do arquivo ou diretório atual. Se chamado na fasepreVisitDirectory, até mesmo o diretório atual é ignorado e opostVisitDirectory não é chamado

Finalmente, deve haver uma maneira de acionar o processo de passagem, talvez quando o usuário clica no botãosearch em uma interface gráfica com o usuário após definir os critérios de pesquisa. Esta é a parte mais simples.

Só temos que chamar a APIwalkFileTree estática da classeFiles e passar para ela uma instância da classePath que representa o ponto de partida da travessia e, em seguida, uma instância de nossoFileVisitor:

Path startingDir = Paths.get("pathToDir");
FileVisitorImpl visitor = new FileVisitorImpl();
Files.walkFileTree(startingDir, visitor);

3. Exemplo de pesquisa de arquivo

Nesta seção, vamos implementar um aplicativo de pesquisa de arquivos usando a interfaceFileVisitor. Queremos tornar possível ao usuário especificar o nome completo do arquivo com extensão e um diretório inicial no qual procurar.

Quando localizamos o arquivo, imprimimos uma mensagem de sucesso na tela e quando toda a árvore de arquivos é pesquisada sem que o arquivo seja encontrado, também imprimimos uma mensagem de falha apropriada.

3.1. A classe principal

Vamos chamar essa classe deFileSearchExample.java:

public class FileSearchExample implements FileVisitor {
    private String fileName;
    private Path startDir;

    // standard constructors
}

Ainda estamos para implementar os métodos de interface. Observe que criamos um construtor que leva o nome do arquivo a ser pesquisado e o caminho para iniciar a pesquisa. Usaremos apenas o caminho inicial como um caso base para concluir que o arquivo não foi encontrado.

Nas subseções a seguir, implementaremos cada método de interface e discutiremos sua função neste aplicativo de exemplo específico.

3.2. A APIpreVisitDirectory

Vamos começar implementando a APIpreVisitDirectory:

@Override
public FileVisitResult preVisitDirectory(
  Path dir, BasicFileAttributes attrs) {
    return CONTINUE;
}

Como dissemos anteriormente, essa API é chamada sempre que o processo encontra um novo diretório na árvore. Seu valor de retorno determina o que acontecerá a seguir, dependendo do que decidirmos. Este é o ponto em que pulamos diretórios específicos e os eliminamos do espaço de amostra de pesquisa.

Vamos escolher não discriminar nenhum diretório e apenas pesquisar em todos eles.

3.3. A APIvisitFile

A seguir, implementaremos a APIvisitFile. É aqui que a ação principal acontece. Essa API é chamada sempre que um arquivo é encontrado. Aproveitamos isso para verificar os atributos do arquivo e comparar com nossos critérios e retornar um resultado apropriado:

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    String fileName = file.getFileName().toString();
    if (FILE_NAME.equals(fileName)) {
        System.out.println("File found: " + file.toString());
        return TERMINATE;
    }
    return CONTINUE;
}

No nosso caso, estamos apenas verificando o nome do arquivo que está sendo visitado para saber se é aquele que o usuário está procurando. Se os nomes corresponderem, imprimimos uma mensagem de sucesso e encerramos o processo. No entanto, há muito o que se pode fazer aqui, especialmente depois de ler o

No entanto, há muito que se pode fazer aqui, especialmente depois de ler a seçãoFile Attributes. Você pode verificar a hora de criação, hora da última modificação ou horas do último acesso ou vários atributos disponíveis no parâmetroattrs e decidir de acordo.

3.4. A APIvisitFileFailed

A seguir, implementaremos a APIvisitFileFailed. Essa API é chamada quando um arquivo específico não está acessível para a JVM. Talvez tenha sido bloqueado por outro aplicativo ou possa ser apenas um problema de permissão:

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    System.out.println("Failed to access file: " + file.toString());
    return CONTINUE;
}

Simplesmente registramos uma mensagem de falha e continuamos com a travessia do restante da árvore de diretórios. Em um aplicativo gráfico, você pode optar por perguntar ao usuário se continua ou não usando uma caixa de diálogo ou simplesmente registrar a mensagem em algum lugar e compilar um relatório para uso posterior.

3.5. A APIpostVisitDirectory

Finalmente, implementaremos a APIpostVisitDirectory. Essa API é chamada toda vez que um diretório é totalmente percorrido:

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc){
    boolean finishedSearch = Files.isSameFile(dir, START_DIR);
    if (finishedSearch) {
        System.out.println("File:" + FILE_NAME + " not found");
        return TERMINATE;
    }
    return CONTINUE;
}

Usamos a APIFiles.isSameFile para verificar se o diretório que acabou de ser percorrido é o diretório de onde iniciamos o percurso. Se o valor de retorno fortrue, significa que a pesquisa foi concluída e o arquivo não foi encontrado. Portanto, encerramos o processo com uma mensagem de falha.

No entanto, se o valor de retorno forfalse, isso significa que acabamos de percorrer um subdiretório e ainda há uma probabilidade de encontrar o arquivo em algum outro subdiretório. Então continuamos com a travessia.

Agora podemos adicionar nosso método principal para executar o aplicativoFileSearchExample:

public static void main(String[] args) {
    Path startingDir = Paths.get("C:/Users/user/Desktop");
    String fileToSearch = "hibernate-guide.txt"
    FileSearchExample crawler = new FileSearchExample(
      fileToSearch, startingDir);
    Files.walkFileTree(startingDir, crawler);
}

Você pode brincar com este exemplo alterando os valores das variáveisstartingDirefileToSearch. QuandofileToSearch existe emstartingDir ou em qualquer um de seus subdiretórios, você receberá uma mensagem de sucesso, caso contrário, uma mensagem de falha.

4. Conclusão

Neste artigo, exploramos alguns dos recursos menos usados ​​disponíveis nas APIs do sistema de arquivos Java 7 NIO.2, particularmente a interfaceFileVisitor. Também conseguimos seguir as etapas de criação de um aplicativo de pesquisa de arquivos para demonstrar sua funcionalidade.

O código-fonte completo dos exemplos usados ​​neste artigo está disponível emGithub project.