Enviar um café pro programador

Pode me ajudar a transformar cafeína em código?

Como ler caracteres, Strings e Bytes de um arquivo em Java

Neste tutorial de nossa apostila Java Progressivo, iremos aprender as diferentes maneiras de se ler dados de um arquivo na linguagem Java.

Iniciaremos mostrando como ler caractere por caractere de um arquivo.
Em seguida, veremos como ler Strings (ler linhas inteiras).
E por fim, veremos como ler quaisquer tipos de bytes de um arquivo, seja seu conteúdo de texto, vídeo, música ou binário.

Como ler caracteres de um arquivo em Java

Inicialmente, crie um arquivo chamado "file.txt", e o bote dentro do projeto de Java, junto das pastas src e bin. Escreve apenas a letra 'a' nesse arquivo.

Para abrir este arquivo, iremos usar a classe FileInputStream que irá receber uma string que representa o local onde está armazenado o arquivo em seu computador.

Como ele está na pasta do próprio projeto, apenas colocamos o nome do arquivo: file.txt
Mas você pode colocar o endereço completo: /usr/JavaProgressivo/Arquivos/file.txt
Vamos chamar de "entrada" o objeto responsável pela abertura do arquivo.

Como queremos trabalhar com caracteres, a maneira que este objeto vai ler o arquivo é uma maneira especial, pois deve ler bytes que representem caracteres.
Vamos usar a classe InputStreamReader para 'tratar' esse objeto que abriu o arquivo, essa classe vai fazer com que a leitura do arquivo seja uma leitura específica, uma leitura de caracteres.
Vamos chamar esse objeto de 'entradaFormatada'.

E, finalmente, para ler o primeiro caractere do arquivo (não importa quantos bytes tenham sido lidos, pois a InputStreamReader já tratou de ler e formatar essa entrada para caractere) iremos usar o método read(), que retorna um inteiro que representa o caractere.

Assim, nosso código que lê esse primeiro caractere fica:

import java.io.*;

public class Arquivos {

 public static void main(String[] args) throws IOException{
     FileInputStream entrada = new FileInputStream("file.txt");
     InputStreamReader entradaFormatada = new InputStreamReader(entrada);
     int c = entradaFormatada.read();
     
     System.out.println(c);
 }

}

O resultado deve ser 97, que é a representação de 'a'.
Para podermos exibir na tela o caractere 'a', basta fazermos o cast para char:
System.out.print( (char) c);

Lendo mais de um caractere - Fim de arquivo

Ok, aprendemos a ler um caractere de um arquivo.
Mas, e para ler outro? Usar o método de novo? Sim, funciona.
E se seu arquivo for um texto enorme, de milhares de caracteres, usar milhares de vezes o read() ?

Óbvio que não.
Podemos usar um looping, como através do laço while, que deve ler todos os caracteres e só parar quando terminar o arquivo.

E como que vamos saber quando termina o arquivo?
Fácil: o maravilhoso método read() retorna o valor -1 quando isso ocorre.
E ele faz outra coisa interessante: após ele ler um caractere, ele imediatamente aponta para o próximo.

Assim, escreva em seu arquivo 'file.txt' o seguinte texto (ou qualquer outro): Apostila Java Progressivo
Para exibir todo o conteúdo de texto de um arquivo, usaremos o seguinte código:

import java.io.*;

public class Arquivos {

 public static void main(String[] args) throws IOException{
     FileInputStream entrada = new FileInputStream("file.txt");
     InputStreamReader entradaFormatada = new InputStreamReader(entrada);
     int c = entradaFormatada.read();
     
     while( c!=-1){
      System.out.print( (char) c);
      c = entradaFormatada.read();
     }
 }

}

PS: Quando você cria o código de leitura de arquivos, automaticamente a IDE insere o 'throws IOException', para tratar eventuais erros e exceções.




Como ler Strings de um arquivo em Java

Muitas vezes se trabalhar com caractere por caractere (como é feito na linguagem C), é algo um pouco chato e trabalhoso.
Por exemplo, no código passado tivemos que criar um laço while para ler uma frase.

Visando facilitar a vida do programador Java, existe uma classe chamada BufferedReader que recebe como argumento um objeto do tipo InputStreamReader e agrupa os caracteres até formar uma linha.
Ou seja, ele recebe os caracteres (entrada formatada) e vai agrupando eles até encontrar o símbolo de new line '\n', e retorna essa String (sem o \n).

Vamos chamar esse objeto da classe BufferedReader de 'entradaString' e vamos ler a primeira e única linha de nosso arquivo 'file.txt':
Também iremos criar a variável 'linha', do tipo String para receber as linhas.
Linhas essas que serão lidas e retornadas através do método readLine().

Note como as coisas são análogas ao caso do caractere.
Lá, quando chegava ao final do arquivo retornava o valor -1, como aqui estamos trabalhando com Strings, ao encontrar o final do arquivo, o método readLine() retorna o nosso velho e conhecido null.

Agora escreva outra linha: "C Progressivo", "HTML Progressivo", "Programação Progressiva" etc.
O código Java para exibir todas essas linhas será:



import java.io.*;

public class Arquivos {

 public static void main(String[] args) throws IOException{
  FileInputStream entrada = new FileInputStream("file.txt");
  InputStreamReader entradaFormatada = new InputStreamReader(entrada);
  BufferedReader entradaString = new BufferedReader(entradaFormatada);
     
  String linha = entradaString.readLine();
  
  while(linha != null){
   System.out.println(linha);
   linha = entradaString.readLine();
  }
 }

}

Como ler bytes de um arquivo em Java

Para ler byte por byte de um arquivo, iremos usar duas classes: a InputStream e a FileInputStream(esta é filha da primeira).
Vamos passar para esta segunda classe o endereço (URL) de nosso arquivo de texto.
Como vamos colocar ele no diretório do projeto (junto as pastas src e bin), fica:
InputStream entrada = new FileInputStream("file.txt");

Isso já abre e posiciona o leitor de bytes apontando para o primeiro byte do arquivo.
Vamos usar um inteiro para receber byte por byte, o "umByte".
Note que, embora ele leia o byte (8 bits), o Java já transforma esta informação em um inteiro (bacana, esse Java, não?)

Para ler um byte, vamos fazer uso do método read(), que lê e retorna o byte do arquivo.
Escrevea no 'file.txt' simplesmente o caractere 'a'.
Nosso programa que lê 1 byte fica:

import java.io.*;

public class Arquivos {

 public static void main(String[] args) throws IOException{
     InputStream entrada = new FileInputStream("file.txt");
     int umByte = entrada.read();
     
     System.out.print(umByte);
 }

}

Note que o resulto é 97, que é o inteiro que representa o caractere 'a'.
Para ver o caractere 'a' aparecer na tela, basta colocar um cast para que o Java automaticamente transforme o inteiro em caractere. Para isso, basta fazer:
System.out.print((char)umByte)

Vamos agora escrever mais coisas em nosso arquivo.
Substitua o 'a' por "Apostila Java Progressivo". Ou seja, agora temos vários, vários bytes para ler.
Para criarmos um programa que leia e exiba todos os bytes, vamos usar um laço que vai rodar até a classe FileInputStream encontrar o final do arquivo, e quando isso ocorrer o método read() retorna o valor, que em inteiro, é -1.
E como o método read(), antes de retornar o byte lido, pula (aponta) para o próximo byte, para lermos todos os bytes de um arquivo de texto, nosso código deve ser:

import java.io.*;

public class Arquivos {

 public static void main(String[] args) throws IOException{
     InputStream entrada = new FileInputStream("file.txt");
     int umByte = entrada.read();
     
     while(umByte != -1){
      System.out.print((char)umByte);
      umByte = entrada.read();
     }
 }

}


Embora tenhamos usado a FileInputStream para ler caracteres, ela pode ser usada para se trabalhar com quaisquer tipos de dados. É tanto que não usamos a InputStreamReader para tratar nossos bytes, como fizemos quando fomos ler caracteres e Strings.

Fechando arquivos - O método close()

Embora a JVM (Java Virtual Machine) tenha um fantástico Garbage Collector, que vai eliminando variáveis que não usamos e fechando arquivos que não mais acessaremos, nem sempre ela consegue prever o que vai ser usado ou não em um programa.

Por isso, independente da complexidade de seus aplicativos Java é importante você fechar os arquivos que abriu (seja pra ler ou escrever).
Isso é feito através do método close(), presentes nas classes que usamos para tratar os arquivos.
Assim, faça:

entrada.close();

9 comentários:

Anônimo disse...

Cara parabéns pela iniciativa de postar esses excelentes conteúdos, continuem assim, esse site é muito bom.

wandermunhe@hotmail.com disse...

Olá!
Antes de mais nada, parabéns pela iniciativa do site.
O meu programa "Arquivos" não está rodando. Ele está dando esta mensagem abaixo:
Exception in thread "main" java.io.FileNotFoundException: file.txt (O sistema não pode encontrar o arquivo especificado)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:131)
at java.io.FileInputStream.(FileInputStream.java:87)
at arquivos.Arquivos.main(Arquivos.java:9)
Java Result: 1

Sabem dizer o que significa?
Obrigado e parabéns pelo curso.

Yuri Jivago disse...

Olá, você criou o arquivo file.txt no local correto (dentro da pasta do projeto)?

Yuri Jivago disse...

wandermunhe "java.io.FileNotFoundException:file.txt" tá dizendo que não está conseguindo encontrar o arquivo "file.txt". Você criou o arquivo no local correto, quero dizer, dentro da pasta do projeto?

Anônimo disse...

Olá! Para criar um arquivo do tipo .txt basta escrever na main
File f = new File ("Texto1.txt");
f.createNewFile();
...
Deste modo, é o próprio programa que está a dar o nome a esse arquivo de "Texto1", certo... mas como faço para pedir ao utilizador do programa, um nome/directório para esse novo arquivo que vai ser criado?

Unknown disse...

O meu dava o mesmo problema.
Mas consegui resolver da seguinte forma.
Na criação do arquivo eu coloquei apenas "file" e no código na hora de abrir coloquei "file.txt" .
A extensão só se coloca depois e não no nome da criação.

Unknown disse...

Olá galera, bem olhem este código que eu fiz. Funciona muito bem. espero ter ajudado. Irei postar a classe FileIO e a Main.

>>>>>>FILEIO.JAVA<<<<<<

package me.hikari.utils.IO;

import java.io.*;

public class FileIO {
private String workPath;

public String readFileFirstLine(String fileName) {
try {
FileInputStream entryFile = new FileInputStream(getWorkPath()+"/"+fileName);
InputStreamReader formatedEntryLine = new InputStreamReader(entryFile);
BufferedReader stringEntry = new BufferedReader(formatedEntryLine);

String line = stringEntry.readLine();

while(line != null) {
System.out.println(line);
line = stringEntry.readLine()+"\n";
return line;
}
entryFile.close();
formatedEntryLine.close();
stringEntry.close();
} catch (IOException e) { e.printStackTrace(); }
return null;
}

public String getWorkPath() {
return this.workPath;
}

public void setWorkPath(String workPath) {
this.workPath = workPath;
}


}

>>>>>>>>>MAIN.JAVA<<<<<<<<<<
package me.hikari.utils.IO;

public class Main
{
private static final String WORK_PATH = "res";
static FileIO fIO = new FileIO();
public static void main(String[] args)
{
fIO.setWorkPath(WORK_PATH);
fIO.readFileFirstLine("test.txt");
}
}

Eu ultilizei de uma constante para determinar a pasta e depois usei ela em conjunto com a outra classe.

idpol disse...

Qdo leio um entendimento de maneira ser assimilada até por quem nunca viu java, só ouviu... é um prazer elogiar e dá até vontade de 'programar'. Diante do que encontro me limito a dar os méritos ao invés de re-inventar a roda. Qdo preciso, peço autorização de uso ou negocio o valor. Show de bola!!!!

Wellington Lins disse...

Muito bom ! Excelente material, eu recomendo a todos!!! Muito obrigado por compartilhar!

Contribuir com o Java Progressivo

Que tal apoiar e fazer crescer o ensino da programação no Brasil ?

Ajudar nosso país a crescer e se desenvolver cada vez mais, tecnologicamente?

Clica abaixo pra saber mais!

Apoiar o Projeto Progressivo


Tutoriais de Java