1. Hierarquia de exceções de entrada/saída
Em Java, ao trabalhar com arquivos e outros recursos externos, quase sempre precisamos lidar com as chamadas exceções de entrada/saída. São objetos que são lançados (throw) quando algo dá errado durante a leitura ou a escrita de dados. Por exemplo, se o arquivo não for encontrado, não houver acesso ou o disco de repente ‘cansou’.
Os protagonistas da nossa aula
Em Java há toda uma hierarquia desse tipo de exceção. Aqui estão as principais:
- IOException — a classe base para todos os erros de entrada/saída. Se algo der errado com arquivos, streams ou rede — quase sempre a “culpada” é ela (ou alguma de suas numerosas subclasses).
- FileNotFoundException — subclasse de IOException, que aparece quando você tenta abrir um arquivo que não existe ou o caminho está incorreto.
Outras derivadas:
- EOFException — também é subclasse direta de IOException. Sinaliza que, durante a leitura, chegamos inesperadamente ao fim do arquivo.
- MalformedInputException — “neto”: herda de CharacterCodingException, que, por sua vez, herda de IOException. Esse erro ocorre quando o arquivo não pode ser corretamente interpretado na codificação indicada (por exemplo, esperava-se "UTF-8", mas chegou uma sequência corrompida).
- Há também SocketException, ZipException e outros “parentes” especializados, cada um com sua área de responsabilidade. Quanto mais fundo na hierarquia, mais estreita e específica é a situação.
Esquema simplificado:
java.lang.Exception
└── java.io.IOException
├── java.io.FileNotFoundException
├── java.io.EOFException
├── java.nio.charset.MalformedInputException
└── ... (outros)
Fato interessante:
Em Java, quase todas as operações com arquivos exigem declarar ou tratar IOException — são as chamadas checked exceptions. O compilador não vai deixar você esquecer o tratamento de erros!
2. Quando e por que essas exceções ocorrem
Abertura de arquivo inexistente
O caso mais comum — você tenta abrir um arquivo e ele não existe. É como chegar ao ponto e o ônibus nem sequer existir na tabela de horários.
FileInputStream fis = new FileInputStream("abracadabra.txt"); // Boom! FileNotFoundException
Tentativa de gravar em arquivo sem permissão
Se você tentar gravar um arquivo em uma pasta na qual não tem permissão, receberá FileNotFoundException ou IOException (dependendo da situação).
FileOutputStream fos = new FileOutputStream("/system/secret.txt"); // Boom! FileNotFoundException ou IOException
Erros de leitura/gravação devido a mídia danificada
Às vezes o arquivo até existe, mas o disco está danificado, o arquivo está sendo usado por outro programa ou a energia caiu de repente — então você receberá IOException com diferentes mensagens.
Outros motivos
- O arquivo está somente para leitura e você tenta escrever.
- O caminho do arquivo é muito longo ou contém caracteres inválidos.
- O arquivo está em uso por outro processo.
- O disco está cheio.
- O arquivo foi excluído por outro processo entre a verificação e o uso.
3. Tratamento com try-catch
Sempre que você trabalhar com arquivos, streams, rede — use try-catch. É como um airbag: se algo der errado, o programa não vai cair, mas poderá reagir corretamente.
Como capturar exceções corretamente?
Em Java, exceções mais específicas devem ser capturadas antes das gerais. Se você colocar primeiro um catch (IOException e) geral, os mais específicos, como FileNotFoundException, simplesmente não serão alcançados — a execução não chegará até eles.
Estrutura correta:
try {
// Trabalho com arquivo
} catch (FileNotFoundException e) {
// Tratamento da situação "arquivo não encontrado"
} catch (IOException e) {
// Tratamento de outros erros de E/S
}
Por que assim?
Porque FileNotFoundException é um caso específico de IOException. Se você capturar o caso geral antes, o específico não chegará ao seu catch.
Exemplo de código: tratamento de erros ao abrir arquivo
import java.io.*;
public class FileReaderExample {
public static void main(String[] args) {
String filename = "notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Primeira linha do arquivo: " + line);
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Arquivo não encontrado: " + filename);
} catch (IOException e) {
System.out.println("Erro ao ler o arquivo: " + e.getMessage());
}
}
}
Atenção:
Mesmo que você tenha verificado que o arquivo existe, sempre mantenha try-catch — o arquivo pode desaparecer a qualquer momento (por exemplo, outro processo pode removê-lo).
4. Prática: escrevendo código com tratamento de erros
Vamos criar exemplos simples e fazer com que reajam corretamente à ausência de arquivo e outros erros.
Passo 1: tentar abrir um arquivo inexistente
import java.io.*;
public class NotesApp {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
System.out.println("Suas notas:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Ops! O arquivo de notas não foi encontrado: " + filename);
System.out.println("Dica: crie o arquivo ou verifique o nome.");
} catch (IOException e) {
System.out.println("Ocorreu um erro ao ler o arquivo: " + e.getMessage());
}
}
}
Passo 2: adicionar tratamento para gravação de arquivo
import java.io.*;
public class NotesWriter {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true)); // append: true
writer.write("Nova nota!\n");
writer.close();
System.out.println("Nota adicionada com sucesso!");
} catch (IOException e) {
System.out.println("Erro ao escrever no arquivo: " + e.getMessage());
}
}
}
Passo 3: exemplo universal com registro (logging) de erros
import java.io.*;
public class SafeFileCopier {
public static void main(String[] args) {
String source = "source.txt";
String target = "target.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(target));
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
reader.close();
writer.close();
System.out.println("Arquivo copiado com sucesso!");
} catch (FileNotFoundException e) {
System.out.println("Arquivo não encontrado: " + e.getMessage());
} catch (IOException e) {
System.out.println("Erro de E/S: " + e.getMessage());
}
}
}
Dica:
Em aplicativos reais, vale a pena registrar (logar) os erros não apenas na tela, mas também em um arquivo de log ou sistema de registros, para depois entender o que exatamente deu errado.
5. Tabela: principais exceções de E/S
| Exceção | Quando ocorre? | Como tratar? |
|---|---|---|
|
Arquivo não encontrado, caminho inexistente, sem permissão | Informar o usuário, verificar caminho/permissões, criar o arquivo se necessário |
|
Fim de arquivo inesperado durante a leitura | Informar sobre corrupção/incompletude, tentar recuperar os dados parcialmente |
|
Erro geral de E/S (disco, permissões, bloqueio) | Verificar detalhes, encerrar a operação corretamente, repetir a tentativa se possível |
|
Codificação ou estrutura de arquivo incorreta | Informar sobre corrupção, tentar outra codificação/fonte |
6. Erros típicos ao tratar exceções de E/S
Erro nº 1: Capturar apenas o Exception geral. É tentador escrever apenas catch (Exception e), mas então você não conseguirá distinguir o que exatamente deu errado. É melhor capturar primeiro as exceções específicas (FileNotFoundException) e depois — a IOException geral.
Erro nº 2: Não fechar streams em caso de erro. Se você abriu um arquivo e ocorreu uma exceção, o stream pode ficar sem ser fechado. Use try-with-resources ou feche os recursos em finally.
Erro nº 3: Ignorar as mensagens das exceções. Não imprima apenas “Erro!”, mostre detalhes: e.getMessage(). Isso ajuda a entender mais rápido o que deu errado.
Erro nº 4: Não tratar FileNotFoundException na gravação. Muitos pensam que FileNotFoundException é apenas para leitura. Na verdade, ele também pode ocorrer na gravação (caminho incorreto, sem permissão para criar o arquivo etc.).
Erro nº 5: Não verificar as permissões de acesso. Se o programa for executado com permissões restritas, muitas operações com arquivos podem falhar. Sempre leve isso em conta e informe o usuário.
GO TO FULL VERSION