Java Ler e Escrever Arquivos

Até aqui, tudo o que seus programas sabiam sumia quando eles terminavam. Com arquivos, o programa lê dados que já existem (uma planilha, um log) e grava resultados que continuam lá depois. Nesta aula você usa o pacote moderno java.nio.file para ler a planilha de alunos da Ana, gravar relatórios, criar pastas e lidar com os erros de arquivo mais comuns.

Você vai aprender
  • Representar caminhos com Path.of, e a diferença entre caminho relativo e absoluto.
  • Ler um arquivo inteiro (Files.readString) ou linha por linha (readAllLines, lines).
  • Gravar (writeString, write) e acrescentar no fim (APPEND).
  • Conferir, criar, listar e apagar: exists, createDirectories, list, delete.
  • Ler e gravar aos poucos com BufferedReader e BufferedWriter, dentro de try-with-resources.
  • O que é a codificação UTF-8 e o erro MalformedInputException.
  • As exceções de arquivo: NoSuchFileException, FileAlreadyExistsException, DirectoryNotEmptyException.

Esta aula usa throws, IOException e try-with-resources. Os programas rodam na pasta pessoal da Ana, /home/ana, onde existem a pasta Documentos e, dentro dela, a planilha alunos.csv e a lista de lembretes notas.txt:

$ cat Documentos/alunos.csv
nome,idade,cidade,nota
Ana,29,Recife,9.5
Bruno,34,Curitiba,7.0
Carla,22,Salvador,8.5
Diego,41,Manaus,6.0
Elisa,27,Porto Alegre,10.0

A ideia antes do código

Um arquivo é como uma gaveta com etiqueta num armário. O caminho é o endereço da gaveta ("armário do escritório, segunda prateleira, gaveta alunos.csv"). Para usar a gaveta, você precisa de duas coisas: saber o endereço (Path) e alguém que abra, leia e guarde coisas nela (a classe Files, cheia de métodos estáticos prontos).

E, como a gaveta pode não estar lá, estar trancada ou o armário pode estar cheio, quase todos os métodos de Files lançam IOException, uma exceção checked. Nos exemplos curtos, o main declara throws IOException; nos programas de verdade, trate com try/catch.


Caminhos: Path

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        Path arquivo = Path.of("Documentos", "alunos.csv");
        System.out.println("Caminho: " + arquivo);
        System.out.println("Nome: " + arquivo.getFileName());
        System.out.println("Pasta: " + arquivo.getParent());
        System.out.println("Absoluto: " + arquivo.toAbsolutePath());
        System.out.println("É absoluto? " + arquivo.isAbsolute());
        System.out.println("Existe? " + Files.exists(arquivo));
        System.out.println("É pasta? " + Files.isDirectory(arquivo));
        System.out.println("Tamanho: " + Files.size(arquivo) + " bytes");
        System.out.println("Existe fotos.zip? " + Files.exists(Path.of("Documentos/fotos.zip")));
    }
}
$ java Main.java
Caminho: Documentos/alunos.csv
Nome: alunos.csv
Pasta: Documentos
Absoluto: /home/ana/Documentos/alunos.csv
É absoluto? false
Existe? true
É pasta? false
Tamanho: 132 bytes
Existe fotos.zip? false
import java.nio.file.Path; e Files;
As duas classes da aula ficam em java.nio.file ("new input/output", a entrada e saída "nova", de 2011). A IOException fica em java.io.
Path.of("Documentos", "alunos.csv")
Monta o caminho juntando as partes com o separador do sistema (/ no Linux e no macOS, \ no Windows). Path.of("Documentos/alunos.csv") também funciona. Java 11+; antes, Paths.get(…).
getFileName(), getParent()
O último pedaço (o nome) e o caminho da pasta que o contém.
toAbsolutePath()
O caminho completo, a partir da raiz /.
Files.exists, isDirectory, size
Perguntas ao sistema de arquivos: existe? é pasta? quantos bytes? Criar um Path não cria nem confere nada: é só um endereço.

Relativo × absoluto

Documentos/alunos.csv é um caminho relativo: ele parte da pasta atual, aquela em que o terminal estava quando o programa foi iniciado (a mesma ideia do pwd no terminal). Um caminho absoluto começa na raiz: /home/ana/Documentos/alunos.csv. Veja o mesmo programa rodado de dentro da pasta java:

$ cd java
$ java Main.java
Caminho: Documentos/alunos.csv
Nome: alunos.csv
Pasta: Documentos
Absoluto: /home/ana/java/Documentos/alunos.csv
É absoluto? false
Existe? false
É pasta? false
Exception in thread "main" java.nio.file.NoSuchFileException: Documentos/alunos.csv
	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
	at java.base/sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:57)
	at java.base/sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:161)
	at java.base/sun.nio.fs.LinuxFileSystemProvider.readAttributes(LinuxFileSystemProvider.java:99)
	at java.base/java.nio.file.Files.readAttributes(Files.java:1702)
	at java.base/java.nio.file.Files.size(Files.java:2242)
	at Main.main(Main.java:15)

O toAbsolutePath() mostra o que aconteceu: o Java procurou em /home/ana/java/Documentos/alunos.csv, que não existe. O exists respondeu false sem reclamar, mas o size precisa do arquivo e lançou NoSuchFileException ("não existe tal arquivo"). Esse é o erro de arquivo mais comum de todos: o caminho está certo, mas o programa foi iniciado em outra pasta.

Um caminho que funciona de qualquer pasta

Para arquivos da pasta pessoal, monte o caminho a partir dela: Path.of(System.getProperty("user.home"), "Documentos", "alunos.csv"). A propriedade user.home vale /home/ana na máquina da Ana (e C:\Users\ana no Windows). Para saber de onde o programa foi iniciado, Path.of("").toAbsolutePath().


Ler um arquivo

Duas formas, para os dois casos mais comuns: o arquivo inteiro num texto só, ou uma lista com uma linha em cada posição.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        String lembretes = Files.readString(Path.of("Documentos/notas.txt"));
        System.out.print(lembretes);
        System.out.println("---");

        List<String> linhas = Files.readAllLines(Path.of("Documentos/alunos.csv"));
        System.out.println("Linhas: " + linhas.size());
        System.out.println("Cabeçalho: " + linhas.get(0));

        double soma = 0;
        for (int i = 1; i < linhas.size(); i++) {
            String[] campos = linhas.get(i).split(",");
            String nome = campos[0];
            double nota = Double.parseDouble(campos[3]);
            System.out.println(nome + " tirou " + nota);
            soma += nota;
        }
        System.out.printf("Média da turma: %.2f%n", soma / (linhas.size() - 1));
    }
}
$ java Main.java
Comprar café
Ligar para o João
Estudar Bash
Fazer backup das fotos
---
Linhas: 6
Cabeçalho: nome,idade,cidade,nota
Ana tirou 9.5
Bruno tirou 7.0
Carla tirou 8.5
Diego tirou 6.0
Elisa tirou 10.0
Média da turma: 8,20
Files.readString(path)
Lê o arquivo inteiro como uma String, com as quebras de linha dentro. Por isso o print (sem ln): o texto já termina com uma quebra. Java 11+
Files.readAllLines(path)
Lê tudo e devolve uma List<String>, uma linha por posição, já sem as quebras. size() é o número de linhas e get(0) a primeira (veja ArrayList).
for (int i = 1; …)
Começa em 1 para pular o cabeçalho.
split(",")
Corta a linha nas vírgulas: campos[0] é o nome, campos[3] a nota (veja Métodos de String).
Double.parseDouble(campos[3])
A nota está como texto no arquivo; vira número (veja Wrappers). O CSV usa ponto, que é o que o parseDouble entende.
printf("%.2f")
A média, em formato brasileiro: 8,20 (veja Formatar Texto).

Os dois métodos carregam o arquivo inteiro na memória. Para arquivos de alguns megabytes, sem problema. Para arquivos enormes (um log de vários gigabytes), leia aos poucos: com Files.lines ou BufferedReader, mais adiante.

Missão: o programa grava uma lista de compras em lista.txt. Complete-o: leia o arquivo de volta com Files.readAllLines e mostre 3 itens: [pão, leite, café] (o tamanho da lista e a própria lista).

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path lista = Path.of("lista.txt");
        Files.writeString(lista, "pão\nleite\ncafé\n");
        // leia o arquivo e mostre quantos itens ele tem
    }
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path lista = Path.of("lista.txt");
        Files.writeString(lista, "pão\nleite\ncafé\n");
        List<String> itens = Files.readAllLines(lista);
        System.out.println(itens.size() + " itens: " + itens);
    }
}

Escrever um arquivo

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path compras = Path.of("Documentos/compras.txt");
        Files.writeString(compras, "pão\nleite\n");
        Files.writeString(compras, "café\n", StandardOpenOption.APPEND);

        Path aprovados = Path.of("Documentos/aprovados.txt");
        List<String> nomes = List.of("Ana", "Carla", "Elisa");
        Files.write(aprovados, nomes);

        System.out.println("Gravei " + Files.size(compras) + " bytes em " + compras);
        System.out.println("Gravei " + nomes.size() + " linhas em " + aprovados);
    }
}
$ java Main.java
Gravei 17 bytes em Documentos/compras.txt
Gravei 3 linhas em Documentos/aprovados.txt
$ cat Documentos/compras.txt
pão
leite
café
$ cat Documentos/aprovados.txt
Ana
Carla
Elisa
$ java Main.java
Gravei 17 bytes em Documentos/compras.txt
Gravei 3 linhas em Documentos/aprovados.txt
$ cat Documentos/compras.txt
pão
leite
café
Files.writeString(path, texto)
Grava o texto no arquivo. Se ele não existe, é criado; se existe, é substituído (o conteúdo antigo se perde). Não pula linha sozinho: os \n são seus.
StandardOpenOption.APPEND
"Acrescentar": grava no fim, mantendo o que já existia. Bom para logs e registros.
Files.write(path, lista)
Grava uma lista de textos, um por linha, com a quebra de linha no fim de cada um. List.of(…) cria uma lista pronta (veja Coleções).

Repare no segundo java Main.java: o arquivo de compras continuou com 3 itens, e não 6. O primeiro writeString substituiu tudo, e o APPEND acrescentou o café de novo. E por que 17 bytes, se são 15 letras e quebras? Porque ã e é ocupam 2 bytes cada na codificação UTF-8 (assunto mais abaixo).

Gravar apaga o que havia

writeString e write sem opções começam o arquivo do zero. Se o arquivo for importante, confira antes com Files.exists, grave com outro nome ou use StandardOpenOption.CREATE_NEW, que lança FileAlreadyExistsException em vez de sobrescrever.


Pastas: criar, listar, apagar

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

public class Main {
    public static void main(String[] args) throws IOException {
        Path pasta = Path.of("Documentos/relatorios/2026");
        Files.createDirectories(pasta);
        Files.writeString(pasta.resolve("outubro.txt"), "Vendas: 1520\n");
        Files.writeString(pasta.resolve("novembro.txt"), "Vendas: 1710\n");

        try (Stream<Path> itens = Files.list(pasta)) {
            for (Path p : itens.sorted().toList()) {
                System.out.println(p.getFileName() + " (" + Files.size(p) + " bytes)");
            }
        }

        try (Stream<String> linhas = Files.lines(Path.of("Documentos/acesso.log"))) {
            System.out.println("O log tem " + linhas.count() + " linhas");
        }

        Files.delete(pasta.resolve("novembro.txt"));
        System.out.println("Ainda existe novembro.txt? " + Files.exists(pasta.resolve("novembro.txt")));
        System.out.println("Apagou? " + Files.deleteIfExists(pasta.resolve("dezembro.txt")));
    }
}
$ java Main.java
novembro.txt (13 bytes)
outubro.txt (13 bytes)
O log tem 6 linhas
Ainda existe novembro.txt? false
Apagou? false
$ ls -R Documentos/relatorios
Documentos/relatorios:
2026

Documentos/relatorios/2026:
outubro.txt
Files.createDirectories(pasta)
Cria a pasta e todas as que faltarem no caminho (relatorios e 2026), como o mkdir -p do terminal. Se já existirem, não faz nada. (createDirectory, no singular, cria só uma e reclama se ela já existe.)
pasta.resolve("outubro.txt")
Um caminho "dentro" de outro: Documentos/relatorios/2026/outubro.txt.
Files.list(pasta)
O conteúdo da pasta, como um Stream<Path>, uma sequência de caminhos que você vai estudar em Streams. Aqui, sorted() ordena por nome e toList() transforma num List comum. O stream mantém a pasta aberta, por isso fica num try-with-resources.
Files.lines(path)
As linhas do arquivo como um Stream<String>, lidas aos poucos (bom para arquivos grandes). count() conta. Também precisa de try-with-resources.
Files.delete(path)
Apaga (arquivo ou pasta vazia). Se não existir, lança NoSuchFileException.
Files.deleteIfExists(path)
Apaga se existir e devolve true; se não existir, devolve false sem exceção.

Atenção: Files.delete apaga de verdade, sem passar pela lixeira.


Aos poucos: BufferedReader e BufferedWriter

Para processar um arquivo linha por linha, sem carregar tudo na memória, e gravar o resultado aos poucos, use um leitor e um escritor "com buffer" (um buffer é uma área de memória intermediária: em vez de ir ao disco a cada letra, o Java lê e grava em blocos). Eles são recursos: precisam ser fechados, e o try-with-resources faz isso. A Ana quer um arquivo só com os aprovados (nota 7 ou mais):

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) {
        Path entrada = Path.of("Documentos/alunos.csv");
        Path saida = Path.of("Documentos/aprovados.csv");
        try (BufferedReader leitor = Files.newBufferedReader(entrada);
             BufferedWriter escritor = Files.newBufferedWriter(saida)) {
            String cabecalho = leitor.readLine();
            escritor.write(cabecalho);
            escritor.newLine();
            String linha;
            int aprovados = 0;
            while ((linha = leitor.readLine()) != null) {
                double nota = Double.parseDouble(linha.split(",")[3]);
                if (nota >= 7.0) {
                    escritor.write(linha);
                    escritor.newLine();
                    aprovados++;
                }
            }
            System.out.println(aprovados + " aprovados gravados em " + saida);
        } catch (IOException e) {
            System.out.println("Erro de arquivo: " + e);
        }
    }
}
$ java Main.java
4 aprovados gravados em Documentos/aprovados.csv
$ cat Documentos/aprovados.csv
nome,idade,cidade,nota
Ana,29,Recife,9.5
Bruno,34,Curitiba,7.0
Carla,22,Salvador,8.5
Elisa,27,Porto Alegre,10.0
Files.newBufferedReader(entrada)
Abre o arquivo para leitura. Fica em java.io.BufferedReader.
Files.newBufferedWriter(saida)
Abre (cria ou substitui) o arquivo para escrita.
leitor.readLine()
Lê a próxima linha, sem a quebra. No fim do arquivo, devolve null.
while ((linha = leitor.readLine()) != null)
A forma clássica: lê uma linha, guarda em linha e, se não for null, executa o corpo. Os parênteses em volta da atribuição são obrigatórios.
escritor.write(texto); escritor.newLine();
Grava o texto e uma quebra de linha.
try ( … ; … )
Os dois recursos são fechados no fim, na ordem inversa. Fechar o escritor é essencial: é no close() que o que sobrou no buffer vai para o disco. Sem ele, o fim do arquivo pode se perder.

Codificação: UTF-8

Um arquivo de texto é uma sequência de bytes. A codificação (charset, encoding) é a tabela que diz qual byte vira qual letra. Para as letras sem acento, quase todas as tabelas concordam. Para ã, é, ç, não. Hoje o padrão do mundo é o UTF-8, em que cada letra acentuada ocupa 2 bytes (por isso o compras.txt tinha 17 bytes).

Os métodos de Files usam UTF-8 quando você não diz nada. E desde o Java 18, UTF-8 é o padrão de todo o Java, em qualquer sistema Java 18+. Arquivos antigos, de programas do Windows, às vezes vêm em ISO-8859-1 (também chamado Latin-1), onde ã é um byte só. A Ana recebeu um assim:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        System.out.println("Codificação padrão: " + Charset.defaultCharset());
        Path antigo = Path.of("Documentos/clientes-antigo.txt");
        System.out.println(Files.readString(antigo, StandardCharsets.ISO_8859_1));
        System.out.println(Files.readString(antigo));
    }
}
$ printf 'Jo\343o;S\343o Paulo\n' > Documentos/clientes-antigo.txt
$ file Documentos/clientes-antigo.txt
Documentos/clientes-antigo.txt: ISO-8859 text
$ java Main.java
Codificação padrão: UTF-8
João;São Paulo

Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 3
	at java.base/java.lang.String.throwMalformed(String.java:1281)
	at java.base/java.lang.String.decodeUTF8_UTF16(String.java:1168)
	at java.base/java.lang.String.newStringUTF8NoRepl(String.java:768)
	at java.base/java.lang.String.newStringNoRepl1(String.java:798)
	at java.base/java.lang.String.newStringNoRepl(String.java:781)
	at java.base/java.lang.System$1.uncheckedNewStringNoRepl(System.java:2129)
	at java.base/java.nio.file.Files.readString(Files.java:3046)
	at java.base/java.nio.file.Files.readString(Files.java:3006)
	at Main.main(Main.java:12)

O printf do terminal criou o arquivo com o byte \343 (o ã do Latin-1), e o comando file confirma: ISO-8859 text. Lendo com StandardCharsets.ISO_8859_1, o texto saiu certo. Lendo com o padrão (UTF-8), aqueles bytes não formam nenhuma letra válida em UTF-8, e o readString lança MalformedInputException ("entrada malformada", uma filha de IOException). Todos os métodos de leitura e escrita de Files aceitam o charset como argumento extra.

Sinais de codificação trocada

Se aparecer MalformedInputException, ou textos como João (UTF-8 lido como Latin-1) ou Jo�o, o arquivo e o programa estão usando tabelas diferentes. Descubra a codificação do arquivo (o comando file ajuda) e passe o StandardCharsets certo. Ao gravar, prefira sempre UTF-8.


Qual método usar

Você quer…Use
Ler um arquivo pequeno inteiroFiles.readString(path)
Ler as linhas de um arquivo pequenoFiles.readAllLines(path)
Ler um arquivo grande, linha a linhaFiles.newBufferedReader ou Files.lines (com try-with-resources)
Gravar um textoFiles.writeString(path, texto)
Gravar uma lista, uma por linhaFiles.write(path, lista)
Acrescentar no fim…, StandardOpenOption.APPEND
Gravar muitas linhas aos poucosFiles.newBufferedWriter (com try-with-resources)
Ler com Scannernew Scanner(path) (veja finally e try-with-resources)
Código antigo com File, FileReader, FileWriterFunciona, mas prefira Path e Files: mensagens de erro melhores e UTF-8 por padrão

Quando dá errado

Todas estas exceções são filhas de IOException, e todas aparecem com o caminho na mensagem.

NoSuchFileException: o arquivo não existe (ali)
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        String texto = Files.readString(Path.of("Documentos/nota.txt"));
        System.out.println(texto);
    }
}
$ java Main.java
Exception in thread "main" java.nio.file.NoSuchFileException: Documentos/nota.txt
	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
	at java.base/sun.nio.fs.UnixFileSystemProvider.newFileChannel(UnixFileSystemProvider.java:213)
	at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:244)
	at java.base/java.nio.file.Files.newByteChannel(Files.java:357)
	at java.base/java.nio.file.Files.newByteChannel(Files.java:399)
	at java.base/java.nio.file.Files.readAllBytes(Files.java:2973)
	at java.base/java.nio.file.Files.readString(Files.java:3043)
	at java.base/java.nio.file.Files.readString(Files.java:3006)
	at Main.main(Main.java:7)

O que aconteceu: o arquivo se chama notas.txt; faltou o s. A mensagem mostra exatamente o caminho que o Java tentou.

Como resolver: confira o nome (maiúsculas e minúsculas contam no Linux), a extensão e a pasta atual (Path.of("").toAbsolutePath()). Num programa para usuários, trate com catch (NoSuchFileException e) e mostre uma mensagem amigável.

DirectoryNotEmptyException e FileAlreadyExistsException
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) {
        Path[] pastas = {Path.of("Documentos/relatorios"), Path.of("Documentos/relatorios/2026")};
        for (Path p : pastas) {
            try {
                Files.delete(p);
                System.out.println("Apaguei " + p);
            } catch (IOException e) {
                System.out.println("Não apaguei: " + e);
            }
        }
        try {
            Files.createDirectory(Path.of("Documentos"));
        } catch (IOException e) {
            System.out.println("Não criei: " + e);
        }
    }
}
$ java Main.java
Não apaguei: java.nio.file.DirectoryNotEmptyException: Documentos/relatorios
Não apaguei: java.nio.file.DirectoryNotEmptyException: Documentos/relatorios/2026
Não criei: java.nio.file.FileAlreadyExistsException: Documentos

O que aconteceu: Files.delete só apaga pastas vazias (relatorios tem 2026, que tem outubro.txt). E createDirectory, no singular, recusa uma pasta que já existe.

Como resolver: apague primeiro o conteúdo (dos arquivos para as pastas). Para criar sem se preocupar, use createDirectories, no plural.

"unreported exception IOException"

O que aconteceu: quase todo método de Files declara throws IOException, uma exceção checked.

Como resolver: acrescente throws IOException no seu método (e o import java.io.IOException;) ou use try/catch. Veja Checked × Unchecked.

O arquivo gravado ficou vazio ou cortado

O que aconteceu: um BufferedWriter que não foi fechado. O que estava no buffer nunca chegou ao disco.

Como resolver: abra o escritor num try-with-resources, para o close() acontecer sempre.


Referência

CódigoO que faz
Path.of("pasta", "arquivo.txt")Monta um caminho
p.getFileName(), getParent(), toAbsolutePath(), resolve("x")Nome, pasta, caminho completo, caminho dentro
Files.exists(p), isDirectory(p), size(p)Existe? É pasta? Quantos bytes?
Files.readString(p)Arquivo inteiro → String
Files.readAllLines(p)Arquivo → List<String>
Files.lines(p)Linhas aos poucos (Stream; try-with-resources)
Files.writeString(p, texto)Grava (cria ou substitui)
Files.write(p, lista)Grava uma linha por item
StandardOpenOption.APPEND / CREATE_NEWAcrescentar / só criar se não existir
Files.createDirectories(p)Cria a pasta e as que faltarem
Files.list(p)Conteúdo de uma pasta (Stream<Path>)
Files.delete(p) / deleteIfExists(p)Apaga (sem lixeira)
Files.copy(a, b) / Files.move(a, b)Copia / move ou renomeia (StandardCopyOption.REPLACE_EXISTING para substituir)
Files.newBufferedReader(p) / newBufferedWriter(p)Leitor e escritor aos poucos (readLine, write, newLine)
Files.readString(p, StandardCharsets.ISO_8859_1)Ler com outra codificação
System.getProperty("user.home")A pasta pessoal

Exercícios

1. O arquivo inteiro

Complete para ler o arquivo inteiro como texto:

String texto = Files.(Path.of("Documentos/notas.txt"));

2. Acrescentar no fim

Complete para gravar no fim do arquivo, sem apagar o que existe:

Files.writeString(log, "nova linha\n", StandardOpenOption.);

3. Fim do arquivo

O que o readLine() de um BufferedReader devolve quando não há mais linhas?

4. O programa usa Path.of("Documentos/alunos.csv") e funciona quando rodado em /home/ana. Rodado em /home/ana/java, lança NoSuchFileException. Por quê?

5. O arquivo log.txt tem 10 linhas. O que acontece com Files.writeString(Path.of("log.txt"), "oi\n")?

6. Por que usar try-with-resources com Files.newBufferedWriter?

Missão final: grave os registros no arquivo notas.csv com Files.write, leia o arquivo de volta com Files.readAllLines, separe cada linha na vírgula e calcule a média das notas. Mostre com printf("Média: %.2f%n", …): no locale brasileiro, Média: 8,33.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path arquivo = Path.of("notas.csv");
        List<String> registros = List.of("Ana,9.5", "Bruno,7.0", "Carla,8.5");
        // 1. grave os registros no arquivo
        // 2. leia as linhas de volta
        // 3. some as notas e mostre a média
    }
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Path arquivo = Path.of("notas.csv");
        List<String> registros = List.of("Ana,9.5", "Bruno,7.0", "Carla,8.5");
        Files.write(arquivo, registros);

        List<String> linhas = Files.readAllLines(arquivo);
        double soma = 0;
        for (String linha : linhas) {
            soma += Double.parseDouble(linha.split(",")[1]);
        }
        System.out.printf("Média: %.2f%n", soma / linhas.size());
    }
}

Resumo

  • Path.of(…) é o endereço; Files faz o trabalho. Quase tudo lança IOException (checked).
  • Caminhos relativos partem da pasta onde o programa foi iniciado; toAbsolutePath() mostra onde o Java está procurando. Para a pasta pessoal, System.getProperty("user.home").
  • Ler: readString (tudo), readAllLines (lista), lines ou BufferedReader (aos poucos).
  • Gravar: writeString e write substituem o arquivo; APPEND acrescenta; BufferedWriter grava aos poucos e precisa ser fechado.
  • Pastas: createDirectories, list, delete (só vazias), deleteIfExists.
  • O padrão é UTF-8; arquivos em outra codificação lançam MalformedInputException: passe o StandardCharsets certo.
  • Erros comuns: NoSuchFileException (nome ou pasta atual errados), FileAlreadyExistsException, DirectoryNotEmptyException.