Entrada e Saída (IO)

Leitura de um arquivo CSV

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.

Leitura e Escrita de um arquivo

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.

Leitura

Aqui usaremos três classes:

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();
        }
    }
}

Escrita

Para escrever em um arquivo usaremos um metodo similar em um caminho contrário:

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();
        }
    }
}

Parse de um CSV

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

Como transformar estas informações em uma lista de animais?

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");



    }

}

Leitura da Entrada Padrão

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)

Leitura de uma 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 + "\"");
    }
}

Leitura de um 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();
        }
    }
}

.