CodeGym /Cursos /JAVA 25 SELF /IOException e FileNotFoundException: tratamento de erros

IOException e FileNotFoundException: tratamento de erros

JAVA 25 SELF
Nível 38 , Lição 0
Disponível

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?
FileNotFoundException
Arquivo não encontrado, caminho inexistente, sem permissão Informar o usuário, verificar caminho/permissões, criar o arquivo se necessário
EOFException
Fim de arquivo inesperado durante a leitura Informar sobre corrupção/incompletude, tentar recuperar os dados parcialmente
IOException
Erro geral de E/S (disco, permissões, bloqueio) Verificar detalhes, encerrar a operação corretamente, repetir a tentativa se possível
MalformedInputException
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.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION