Atualizado: 21/09/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Leitura e Escrita de Arquivos em Java com FileInputStream e FileOutputStream

Escrita de Arquivos com a Classe FileOutputStream

A classe FileOutputStream é projetada para escrever bytes em um arquivo. Como uma subclasse de OutputStream, ela herda toda a sua funcionalidade.

O arquivo de destino é especificado no construtor da classe FileOutputStream. Existem diversas opções de construtores, sendo as mais comuns:

FileOutputStream(String filePath)
FileOutputStream(File fileObj)
FileOutputStream(String filePath, boolean append)
FileOutputStream(File fileObj, boolean append)

O arquivo pode ser definido por meio de uma string com seu caminho ou por um objeto do tipo File. O segundo parâmetro, append, determina o modo de escrita: se for true, os novos dados serão adicionados ao final do arquivo existente; se for false, o conteúdo do arquivo será completamente sobrescrito.

A seguir, um exemplo de como gravar uma string em um arquivo:

import java.io.*;

public class Program {

    public static void main(String[] args) {

        String text = "Hello world!"; // Texto que será gravado no arquivo
        try (FileOutputStream fos = new FileOutputStream("notes.txt")) {
            // Converte a string em bytes usando o charset padrão da plataforma
            byte[] buffer = text.getBytes();

            fos.write(buffer, 0, buffer.length);
            System.out.println("The file has been written");
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

Neste código, um objeto FileOutputStream é criado com o caminho do arquivo de destino. Se o arquivo não existir, ele será criado automaticamente. Como o objetivo é gravar uma string, primeiro ela é convertida em um array de bytes com o método getBytes(). Em seguida, o método write é chamado para gravar esses bytes no arquivo.

A utilização da estrutura try-with-resources para instanciar o FileOutputStream garante que o arquivo seja fechado e seus recursos liberados automaticamente ao final do bloco, mesmo que ocorram exceções.

Não é necessário gravar o array de bytes inteiro de uma vez. Uma versão sobrecarregada do método write() permite a escrita de um único byte:

fos.write(buffer[0]); // Grava apenas o primeiro byte do array

Leitura de Arquivos com a Classe FileInputStream

Para ler dados de um arquivo, a classe FileInputStream é utilizada. Ela herda da classe InputStream e, portanto, implementa todos os seus métodos.

A forma mais comum de criar um objeto FileInputStream é por meio do construtor que aceita o caminho do arquivo como parâmetro:

FileInputStream(String fileName) throws FileNotFoundException

Se o arquivo não puder ser aberto, por exemplo, por não existir no caminho especificado, uma exceção do tipo FileNotFoundException será lançada.

O exemplo a seguir demonstra como ler os dados do arquivo gravado anteriormente e exibi-los no console:

import java.io.*;

public class Program {

    public static void main(String[] args) {

        try (FileInputStream fin = new FileInputStream("notes.txt")) {
            int byteLido;
            // Lê byte a byte até o final do arquivo (-1)
            while ((byteLido = fin.read()) != -1) {
                System.out.print((char) byteLido);
            }
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

Neste caso, cada byte é lido individualmente. A expressão (byteLido = fin.read()) != -1 é um padrão comum em Java: o método read() lê um byte e retorna seu valor inteiro. Quando o método retorna -1, significa que o final do stream foi alcançado. Cada byte lido é então convertido para um caractere (char) e impresso no console.

Outra abordagem, mais eficiente para arquivos maiores, é ler os dados em um array de bytes, conhecido como buffer:

import java.io.*;

public class Program {

    public static void main(String[] args) {

        try (FileInputStream fin = new FileInputStream("notes.txt")) {
            byte[] buffer = new byte[256];
            System.out.println("File data:");

            int bytesLidos;
            while ((bytesLidos = fin.read(buffer)) != -1) {
                // Imprime apenas os bytes que foram efetivamente lidos
                for (int i = 0; i < bytesLidos; i++) {
                    System.out.print((char) buffer[i]);
                }
            }
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

Essa abordagem é mais eficiente, pois minimiza o número de chamadas ao sistema operacional para ler o arquivo. O método read(buffer) tenta preencher o array e retorna o número de bytes que foram efetivamente lidos. A variável bytesLidos armazena esse valor, garantindo que o laço for processe apenas os dados válidos, já que a última leitura pode não preencher o buffer completamente.

Exemplo Prático: Copiando um Arquivo

Combinando as duas classes, é possível ler dados de um arquivo e escrevê-los em outro, realizando uma cópia de forma eficiente.

import java.io.*;

public class Program {

    public static void main(String[] args) {

        try (FileInputStream fin = new FileInputStream("notes.txt");
             FileOutputStream fos = new FileOutputStream("notes_new.txt")) {
            byte[] buffer = new byte[256];

            int bytesLidos;
            // Lê um bloco de dados do arquivo de origem
            while ((bytesLidos = fin.read(buffer)) != -1) {
                // Grava o bloco lido no arquivo de destino
                fos.write(buffer, 0, bytesLidos);
            }
            System.out.println("File has been copied");
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

Neste exemplo, o bloco try-with-resources gerencia ambos os streams. O laço while lê blocos de dados do arquivo de origem para o buffer e, em seguida, o método fos.write(buffer, 0, bytesLidos) grava exatamente a quantidade de bytes lida no arquivo de destino.

É fundamental notar que FileInputStream e FileOutputStream operam com bytes brutos. Por essa razão, são a escolha ideal para arquivos binários (como imagens, áudios ou executáveis). Para manipular arquivos de texto, onde a codificação de caracteres é crucial, as classes FileReader e FileWriter são mais apropriadas e seguras.


Resumo

  • FileOutputStream é usado para escrever bytes em um arquivo, com a opção de adicionar dados ao final (append) ou sobrescrever o conteúdo.
  • FileInputStream é usado para ler bytes de um arquivo. O método read() retorna -1 para indicar o final do arquivo.
  • A leitura de dados em um buffer (um array de bytes) é mais eficiente do que a leitura byte a byte, pois reduz o número de acessos ao disco.
  • A estrutura try-with-resources é a forma recomendada para gerenciar streams, garantindo seu fechamento automático.
  • Embora funcionem para texto, essas classes são mais indicadas para dados binários, onde a manipulação de bytes brutos é necessária.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com