Usar a API Stream com NIO.2

A API NIO.2 (New I/O) do Java introduz várias melhorias para trabalhar com arquivos e diretórios, incluindo a classe Paths, Files, e Path. Quando combinada com a API Stream, ela permite processar arquivos e diretórios de maneira eficiente, usando recursos como o Stream para ler, manipular e modificar dados de arquivos.

Abaixo estão alguns exemplos práticos de como usar a API Stream junto com NIO.2.


1. Listando Arquivos em um Diretório com Stream

Podemos usar a classe Files para listar arquivos em um diretório e aplicar operações de fluxo (Stream) sobre esses arquivos.

Exemplo de listagem de arquivos em um diretório:

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class NIOStreamListarArquivos {
  public static void main(String[] args) {
    // Define o caminho do diretório
    Path caminhoDiretorio = Paths.get("exemplo/diretorio");

    try (Stream<Path> caminhos = Files.walk(caminhoDiretorio)) {
      // Filtra apenas arquivos e imprime seus nomes
      caminhos.filter(Files::isRegularFile)
              .forEach(caminho -> System.out.println(caminho.getFileName()));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
  • Explicação: O método Files.walk() retorna um Stream<Path> contendo todos os caminhos dentro do diretório. O método filter(Files::isRegularFile) filtra apenas os arquivos (não diretórios), e forEach() é usado para imprimir o nome de cada arquivo.

2. Lendo Arquivos com Stream

Você também pode usar a API Stream para ler o conteúdo de um arquivo linha por linha.

Exemplo de leitura de um arquivo com Stream:

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class NIOStreamLerArquivo {
  public static void main(String[] args) {
    // Define o caminho do arquivo
    Path caminhoArquivo = Paths.get("exemplo/diretorio/arquivo.txt");

    try (Stream<String> linhas = Files.lines(caminhoArquivo)) {
      // Processa cada linha do arquivo
      linhas.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
  • Explicação: O método Files.lines() retorna um Stream<String> com as linhas do arquivo. Você pode então processar as linhas do arquivo como qualquer outro stream, por exemplo, com forEach() para imprimir.

3. Filtrando Arquivos por Extensão

Você pode usar a API Stream para filtrar arquivos com base em uma condição, como a extensão do arquivo.

Exemplo de filtragem de arquivos por extensão:

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class NIOStreamFiltrarArquivos {
  public static void main(String[] args) {
    // Define o caminho do diretório
    Path caminhoDiretorio = Paths.get("exemplo/diretorio");

    try (Stream<Path> caminhos = Files.walk(caminhoDiretorio)) {
      // Filtra arquivos com extensão ".txt" e imprime seus nomes
      caminhos.filter(p -> p.toString().endsWith(".txt"))
              .forEach(caminho -> System.out.println(caminho.getFileName()));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
  • Explicação: A filtragem filter(p -> p.toString().endsWith(".txt")) seleciona apenas arquivos com a extensão .txt.

4. Copiando Arquivos Usando Stream

Você pode combinar Stream com a operação de cópia de arquivos para processar e copiar arquivos de um diretório para outro.

Exemplo de cópia de arquivos com Stream:

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class NIOStreamCopiarArquivos {
  public static void main(String[] args) {
    Path origem = Paths.get("exemplo/diretorio");
    Path destino = Paths.get("exemplo/diretorio_destino");

    try (Stream<Path> caminhos = Files.walk(origem)) {
      // Cria o diretório de destino, se não existir
      if (!Files.exists(destino)) {
        Files.createDirectories(destino);
      }

      // Copia os arquivos para o novo diretório
      caminhos.filter(Files::isRegularFile)
              .forEach(caminhoOrigem -> {
                Path caminhoDestino = destino.resolve(origem.relativize(caminhoOrigem));
                try {
                  Files.copy(caminhoOrigem, caminhoDestino);
                  System.out.println("Arquivo copiado: " + caminhoDestino);
                } catch (IOException e) {
                  e.printStackTrace();
                }
              });
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

  • Explicação: O método Files.copy() é usado para copiar arquivos de um diretório para outro. O método resolve() combina o diretório de destino com o caminho relativo do arquivo.

5. Concatenando o Conteúdo de Vários Arquivos com Stream

Você pode concatenar o conteúdo de vários arquivos em um único fluxo usando Stream.concat().

Exemplo de concatenação de arquivos:

import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;

public class NIOStreamConcatenarArquivos {
  public static void main(String[] args) {
    Path caminhoArquivo1 = Paths.get("exemplo/diretorio/arquivo1.txt");
    Path caminhoArquivo2 = Paths.get("exemplo/diretorio/arquivo2.txt");

    try (Stream<String> stream1 = Files.lines(caminhoArquivo1);
         Stream<String> stream2 = Files.lines(caminhoArquivo2)) {
      
      // Concatena os dois streams e imprime o conteúdo
      Stream<String> concatenado = Stream.concat(stream1, stream2);
      concatenado.forEach(System.out::println);
      
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
  • Explicação: O método Stream.concat() concatena dois fluxos de dados. Nesse exemplo, concatenamos os fluxos de duas linhas de arquivos e os imprimimos.

📝 Resumo das Operações com Stream e NIO.2

  • Listar Arquivos em um Diretório: Usamos Files.walk() para obter um fluxo de arquivos e diretórios.
  • Ler Arquivos: Usamos Files.lines() para ler um arquivo linha por linha como um fluxo de dados.
  • Filtrar Arquivos: Aplicamos filtros no fluxo de arquivos, como por exemplo, com a extensão .txt.
  • Copiar Arquivos: Usamos o Stream para copiar arquivos de um diretório para outro.
  • Concatenar Arquivos: Usamos Stream.concat() para combinar o conteúdo de dois ou mais arquivos.

🧪 Quiz – 5 Questões Rápidas

  1. Qual método você usaria para listar arquivos de um diretório como um fluxo?
    A) Files.walk()
    B) Files.list()
    C) Files.scan()
    D) Files.find()

  1. Como você pode ler um arquivo linha por linha usando a API NIO?
    A) Files.readLines()
    B) Files.lines()
    C) Files.stream()
    D) Files.readAllLines()

  1. Qual método você usaria para copiar um arquivo para outro diretório?
    A) Files.move()
    B) Files.copy()
    C) Files.transfer()
    D) Files.save()

  1. Qual método é usado para concatenar dois fluxos de dados?
    A) Stream.concat()
    B) Stream.merge()
    C) Stream.add()
    D) Stream.join()

  1. Como você pode filtrar arquivos com extensão .txt em um diretório?
    A) Files.walk().filter(p -> p.endsWith(".txt"))
    B) Files.walk().filter(p -> p.toString().endsWith(".txt"))
    C) Files.walk().filter(p -> p.contains(".txt"))
    D) Files.walk().filter(p -> p.getFileName().equals(".txt"))

Gabarito Comentado

  1. AFiles.walk() é o método correto para listar arquivos em um diretório como um fluxo.
  2. BFiles.lines() é usado para ler um arquivo linha por linha como um fluxo de strings.
  3. BFiles.copy() é o método para copiar um arquivo para outro diretório.
  4. AStream.concat() é o método usado para concatenar dois fluxos de dados.
  5. BFiles.walk().filter(p -> p.toString().endsWith(".txt")) filtra arquivos com a extensão .txt.