Vamos ver como funciona a leitura de um arquivo e dar um exemplo de como transformar dados de uma tabela em uma lista de objetos.
Existem várias maneiras de ler um arquivo, a técnica usada aqui, apesar de verbosa (usar vários objetos e precisar escrever muito) pode funcionar em versões mais antigas de java.
De qualquer maneira, não existe mistério, qualquer uma que você souber usar e funcionar estará correta.
Aqui usaremos três classes:
FileInputStream
é um InputStream
: recebe um caminho e lê uma cadeia de bytes.InputStreamReader
: recebe um InputStream
e uma codificação, usa esta codificação para transformar os bytes em characteres.BufferedReader
: recebe um InputStreamReader
e é um facilitador, esta classe nos dá a possibilidade de ler cada linha de um arquivo, ou cada palavra. Sem ela teríamos que ler cada character.Por exemplo:
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; public class AcessoDados { public static void leArquivo(String filePath){ try ( InputStream is = new FileInputStream(filePath); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr); ){ String linha; int i=0; while((linha = br.readLine()) != null){ System.out.println("linha " + i++); String[] palavras = linha.split(","); for(String p: palavras){ System.out.println("palavra: " + p); } } }catch(IOException e){ e.printStackTrace(); } } }
Para escrever em um arquivo usaremos um metodo similar em um caminho contrário:
FileOutputStream
é um OutputStream
: recebe um caminho para abrir um arquivo,
new FileOutputStream(filePath);
,new FileOutputStream(filePath, true);
OutputStreamWriter
: recebe um OutputStream
e uma codificação, para saber em qual codificação o arquivo será escrito.PrintWriter
recebe um OutputStreamWriter
, e será um facilitador para que possamos usar os métodos que já conhecemos, como println
. OBS um PrintWriter
deve ser criado com new PrintWriter(osw, true);
, sendo o segundo argumento a opção de usar flush
a cada comando. flush
é o comando para que ele abra o arquivo, escreva e salve o que foi escrito imediatamente. Se não ele não "salva" o que ele escrever.Por exemplo:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.List; public class AcessoDados { public static void saveArquivo(List<String> linhas, String filePath){ try( OutputStream os = new FileOutputStream(filePath); OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8); PrintWriter pw = new PrintWriter(osw, true); ){ for(String linha: linhas){ pw.println(linha); } }catch(IOException e){ e.printStackTrace(); } } }
Um CSV é um padrão de arquivo de texto que representa uma tabela.
Cada linha representa uma linha de um tabela em que cada coluna são as palavras da linha separadas por vírgula.
Por exemplo, uma tabela com informações de animais, em cada linha é um animal e temos as informações de nome, idade e peso
Nome | Idade | Peso |
---|---|---|
brutinho | 10 | 5.5 |
oggi | 5 | 3.8 |
pato donald | 30 | 12.1 |
francis | 7 | 2.0 |
é representada pelo arquivo texto
brutinho,10,5.5 oggi,5,3.8 pato donald,30,12.1 francis,7,2.0
Primeiro vamos fazer a classe Animal
para representar um animal
public class Animal { private String nome; private int idade; private double peso; public Animal(String aNome, int aIdade, double aPeso) { this.nome = aNome; this.idade = aIdade; this.peso = aPeso; } public String getNome() { return nome; } public int getIdade() { return idade; } public double getPeso() { return peso; } @Override public String toString() { return "Animal{" + "nome=" + nome + ", idade=" + idade + ", peso=" + peso + '}'; } }
Agora podemos fazer uma classe com funções para ler o CSV e retornar uma lista de animais. Ou receber uma lista de animais e escrever um CSV.
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public class AcessoDados { public static List<Animal> loadAnimais(String filePath){ List<Animal> animais = new ArrayList<>(); try ( InputStream is = new FileInputStream(filePath); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr); ){ String linha; int i=0; while((linha = br.readLine()) != null){ System.out.println("linha " + i++); String[] palavras = linha.split(","); for(String p: palavras){ System.out.println("palavra: " + p); } String nome = palavras[0]; int idade = Integer.parseInt(palavras[1]); double peso = Double.parseDouble(palavras[2]); Animal animal = new Animal(nome, idade, peso); animais.add(animal); } }catch(IOException e){ e.printStackTrace(); } return animais; } public static void saveAnimais(List<Animal> animais, String filePath){ try( OutputStream os = new FileOutputStream(filePath/*, true*/); OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8); PrintWriter pw = new PrintWriter(osw, true); ){ for(Animal animal: animais){ pw.println(animal.getNome()+","+animal.getIdade()+","+animal.getPeso()); } }catch(IOException e){ e.printStackTrace(); } } }
Supondo que o arquivo animais.csv
está dentro de uma pasta files
, que está dentro da pasta raíz do projeto, podemos usar estas funções da seguinte maneira:
import java.util.List; public class TesteAcessoDados { public static void main(String[] args) { List<Animal> animais = AcessoDados.loadAnimais("files/animais.csv"); System.out.println(""); System.out.println("No teste animais"); for(Animal animal: animais){ System.out.println(animal); } animais.add(new Animal("vacilo", 15, 10)); animais.add(new Animal("francis", 7, 2)); System.out.println(""); System.out.println("No teste animais depois de incluir um animal novo"); for(Animal animal: animais){ System.out.println(animal); } for(int i=0; i<animais.size(); i++){ Animal animal = animais.get(i); if(animal.getNome().equals("vacilo")){ animais.remove(i); break; } } System.out.println(""); System.out.println("No teste animais depois de retirar o vacilo"); AcessoDados.saveAnimais(animais, "files/animais.csv"); } }
Raras vezes na sua vida você vai precisar fazer leitura da entrada padrão em um programa.
Normalmente entradas para um programa são arquivos grandes e estarão guardados em um arquivo externo. E mesmo que não seja grande, não é prático ficar reescrevendo a entrada no terminal sempre que você precisar testar o programa.
Mesmo assim, no começo do aprendizado de programação, por falta de outros meios, devemos recorrer à entrada padrão.
Neste tutorial vamos recorrer à função mais simples da entrada padrão, que é ler uma String
, e depois se preocupar qual é o formato da entrada (se essa String
é um int
, double
, String
, etc...)
Vamos usar o Scanner
da entrada padrão (System.in
)
String
import java.util.Scanner; class EntradaString{ public static void main(String[] args){ Scanner in = new Scanner(System.in); System.out.println("Entre com uma frase:"); String frase = in.nextLine(); System.out.println("A frase entrada foi: \"" + frase + "\""); } }
int
Aqui lemos uma String e verificamos que podemos transformar essa String em um inteiro, caso não seja possível, chamamos a função novamente.
import java.util.Scanner; class EntradaInt{ public static void main(String[] args){ Scanner in = new Scanner(System.in); int numero = leInteiro(); System.out.println("O inteiro entrado foi: \"" + numero + "\""); } static int leInteiro(){ Scanner in = new Scanner(System.in); System.out.println("Entre com um inteiro:"); String numeroString = in.nextLine(); try{ int numeroInteiro = Integer.parseInt(numeroString); return numeroInteiro; }catch(NumberFormatException e){ System.out.println("O valor entrado nao eh um inteiro: " + numeroString); return leInteiro(); } } }
.