Streams Profa. Patrícia A. Jaques [email protected] Unisinos Lendo do Console com a classe Scanner import java.util.Scanner; public class TestaScanner { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println("Digite um numero:"); String numero = scanner.nextLine(); System.out.println("O numero digitado foi:" + numero); } } Laboratório 2 - Patrícia Jaques 2 Entrada e saída de dados em Java • A maioria dos programas precisa acessar e enviar dados externos ao programa. • Os dados de entrada podem ser provenientes de um arquivo em disco, de um teclado ou de uma conexão em rede. • Java permite lidar com todos os tipos de entrada e saída através de uma abstração conhecida como stream. arquivo Uma stream Programa Laboratório 2 - Patrícia Jaques 3 Manipulação de Dados em um Computador • Armazenamento em array é temporário – • Armazenar dados em memória secundária (persistente) – • • • • dados são perdidos quando programa finaliza a execução editor de texto Computador processa informação como 0 e 1 – bit menor unidade do computador – manipulado por circuitos Programador: – incômodo programar em bits – trabalham com conjunto de caracteres do computador: letras, números e símbolos especiais Conjunto de caracteres: – como computador só trabalha com 0 e 1, cada caractere é representado por um padrão de 0e1 – Byte: 8 bits Formatos para caracteres: – ASCII (American Standard Code for Information Interchange): caracteres representados por 1 byte – UNICODE: caracteres representados por 2 bytes Laboratório 2 - Patrícia Jaques 4 Tabela ASCII Laboratório 2 - Patrícia Jaques 5 Arquivo • Na visão do sistema operacional, um arquivo é conjunto de bytes. • A organização dos bytes em um arquivo é uma visão criada pelo aplicativo. – arquivo ppt – arquivo ASCII – conjunto de registros em um arquivo de banco de dados • Java vê arquivo como um fluxo seqüencial de bytes – Cada arquivo acaba com um marcador de fim: que Java avisa ao programador através de exceção ou do valor devolvido pelo método que processa (lê) o arquivo. • Trabalhando com arquivos em Java: – Abrir o arquivo – Processar o arquivo (ler seus bytes até o final do arquivo) ou escrever no arquivo – Fechar o arquivo Laboratório 2 - Patrícia Jaques 6 Streams de Leitura 010010101 010101010 010100101 010100101 010101010 10101 Uma stream bytes ou caracteres Streams de Escrita Programa bytes ou caracteres Programa J J 010010101 010101010 010100101 010100101 010101010 10101 Laboratório 2 - Patrícia Jaques 7 Streams são unidirecionais • O pacote java.io define um grande número de classes para ler e escrever streams. – import java.io.*; • Streams são unidirecionais – Streams para leitura – Stream para escrita • Streams permitem: – acesso seqüencial dos dados do arquivo: • programa lê os dados a partir do início do arquivo • lê todos os dados consecutivamente até encontrar dado procurado ou chegar no final do arquivo • Não permite voltar ao início do arquivo para lê-lo novamente: necessário fechar e reabrir o arquivo. – acesso aleatório dos dados do arquivo: • permite reposicionar ponteiro do arquivo (o número que indica a posição do próximo byte do arquivo a ser lido ou gravado) para voltar ao início do arquivo ou diretamente a uma outra posição. Laboratório 2 - Patrícia Jaques 8 Lendo Bytes e Caracteres Bytes • As classes InputStream e OutputStream, bem como as suas subclasses, são usadas para ler e escrever stream de bytes; Quando usar: para ler e Classes abstratas escrever dados binários, InputStream – Ler tais como imagens e sons OutputStream - Escrever • As classes Reader e Writer (e subclasses) são usadas para ler e escrever streams de caracteres (2 bytes). Caracteres Classes abstratas Reader – Ler Writer - Escrever Quando usar: para ler e escrever dados textuais Laboratório 2 - Patrícia Jaques 9 Obtendo as propriedades de um arquivo – import java.io.File; import java.util.Date; import java.text.*; class TestaArquivo { public static void main (String args []) { File f = new File ("C:/Documents and Settings/Patricia Jaques/Mes documents/Cursos/ CursoJava/ExerciciosApostila/03_Poo/Circle.java"); System.out.println ("Nome do arquivo: "+f.getName ()); nome System.out.println ("Caminho: "+f.getPath ()); // retorna diretório denotado pelo System.out.println ("Caminho Absoluto: "+f.getAbsolutePath ()); // consulta SO System.out.println ("Diretório pai: "+f.getParent ()); System.out.println (f.exists() ? "existe":"não existe"); System.out.println (f.canWrite() ? "pode ser gravado":"não pode ser gravado"); System.out.println (f.canRead() ? "pode ser lido":"não pode ser lido"); System.out.println (f.isDirectory () ? "é diretório":"não é diretório"); DateFormat df = new SimpleDateFormat ("dd/MM/yyyy"); Date data = new Date (f.lastModified ()); System.out.println ("Ultima modificação do arquivo: (data)); Laboratório 2 - "+df.format Patrícia Jaques 10 Listando diretórios import java.io.File; class ListaDir { public static void main (String args [ ]) { String nomeDir = "."; File f1 = new File (nomeDir); if (f1.isDirectory ( )) { System.out.println ("Diretório "+nomeDir); String s[ ] = f1.list( ); for (int i=0; i<s.length; i++) { File f = new File (s[i]); System.out.print (s[i]); if (f.isDirectory ( )) System.out.println (" <dir> "); else System.out.println (" <file>"); } } else System.out.println (nomeDir + " não é um diretório."); } } // da class Laboratório 2 - Patrícia Jaques 11 Trabalhando com Arquivo Texto Lendo e escrevendo texto • A plataforma armazena caracteres segundo convenção Unicode. As classes filhas das classes Reader e Writer convertem os caracteres Unicode de e para o formato de caractere usado pela plataforma (geralmente ASCII-8). Laboratório 2 - Patrícia Jaques 13 Escrita Leitura Hierarquia de Classes de Reader e Writer PrintWriter Laboratório 2 - Patrícia Jaques 14 Trabalhando com caracteres – Reader e • Reader • int read() • int read(char cbuf[]) • int read(char cbuf[], int offset, int length) • Writer novas • void write(int c) • void write(char cbuf[]) • void write(char cbuf[], int offset, int length) • void write(String str) • void write(String str, int off, int len) Laboratório 2 - Patrícia Jaques 15 FileReader e FileWriter • FileReader: – Para ler arquivos textos – FileReader (File file) – FileReader (String fileName) • FileWriter – – – – – Para escrever em arquivos textos FileWriter (File file) FileWriter (File file, boolean append) FileWriter (String fileName) FileWriter (String fileName, boolean append) Laboratório 2 - Patrícia Jaques 16 Lendo Arquivos Textos • Caracteres são armazenados em buffers após serem lidos. • BufferedReader – FileReader fr = new FileReader (filename); – BufferedReader in = new BufferedReader (fr); – Método “String readLine()”: Retorna a próxima linha de texto do arquivo; Laboratório 2 - Patrícia Jaques 17 Lendo linhas de um arquivo texto import java.io.*; public class LeArquivo { public static void main(String args[]) { String filename = "E:\\aulas\\lab2\\t1.txt"; try { FileReader fr = new FileReader(filename); BufferedReader in = new BufferedReader(fr); String line = in.readLine(); while (line != null) { System.out.println(line); line = in.readLine(); } in.close(); } catch (FileNotFoundException e) { System.out.println("Arquivo \""+filename+"\" não existe."); } catch (IOException e) { System.out.println("Erro na leitura do arquivo " + filename+"."); } } } Laboratório 2 - Patrícia Jaques 19 Método Split class BuscaPalavrasEmUmaString { public static void main (String args[ ]) { String texto = "Isto#é#um#texto#de#teste"; // usando delimitador # String result[] = texto.split("#"); for (int i=0; i<result.length; i++) { System.out.println (i+1+": "+result[i]); } } // main } // class c:\> java BuscaPalavrasEmUmaString 1: Isto 2: é 3: um 4: texto 5: de 6: teste Laboratório 2 - Patrícia Jaques 20 Exercício 2 – Separando Tokens • • Crie uma classe chamada Book Esta classe vai ter os seguintes atributos: – – – – – • String title; String isbn; String publisherId; String url; float price; Leia o arquivo Books.txt e guarde os dados de cada linha dentro de um objeto Book. Para fazer isso: – Leia uma linha por vez com o método readLine( ) da classe BuffererReader • – – Cada linha da tabela é uma linha do arquivo. Cada coluna do arquivo é uma string da linha separa pelo delimitador ‘|’ (pipe). • • – • Para obter esta string use o método split da classe String. Ex: String result [ ] = line.split(“\\|”); Cada token do split() vai ser um dado do objeto Book, de acordo com a sua ordem. O primeiro token vai ser sempre o title e assim por diante: • • • • • • • Line = in.readLine(); String title = result[0]; String isbn = result[1]; …. Book b = new Book(); b.setTitle(title); … Crie uma array de books (ou vector) para guardar todos os objetos e percorra essa array imprimindo o conteúdo de seus objetos Laboratório 2 - Patrícia Jaques 21 Não esqueça de importar o pacote java.io.*; PrintWriter void println (String x) void println (int x) … métodos construtores • • • • • • PrintWriter (OutputStream out) PrintWriter (Writer out) // default=sem flush automático, nem para método println PrintWriter (Writer out, boolean autoFlush) – autoflush == true à dá flush com método println – só da flush com o método println e não com o caracter /n converte caractereres UNICODE Java para formato de caracter da plataforma onde o programa Java está executando Laboratório 2 - Patrícia Jaques 22 Escrevendo linhas em um arquivo texto import java.io.*; class EscreveArquivo { public static void main (String args [ ]) { try { File f = new File ("MeuArquivo.txt"); FileWriter fr = new FileWriter (f); PrintWriter out = new PrintWriter (fr); out.println ("Curso de Java: Arquivo gerado pelo programa."); out.close(); } catch (IOException e) { System.out.println ("Erro ao escrever arquivo."); } } } Laboratório 2 - Patrícia Jaques 23 Exercício de Agenda de contatos • O sistema de agenda deve manter uma lista de contatos. • Um contato padrão tem: nome, e-mail, telefone, endereço e data do aniversário. Porém o contato pode ser enquadrado como de algum tipo específico: geral, cliente ou fornecedor. Para fornecedor, é interessante manter-se um índice de qualidade, pois pode ser necessário ter de escolher 1 entre vários fornecedores de um mesmo produto. Já para o cliente, deve-se atribuir uma data da última compra e uma classificação de fidelidade (ou valores possíveis são: fiel, freqüente, pouco freqüente e apenas uma vez). Por fim, da categoria geral, não é necessário guardar mais nenhum dado além dos do contato. • O programa da agenda deve manter um menu de opções do programa: incluir contato (acrescenta numa lista de contatos ordenados por nome), excluir contato (retirar da lista), listar contatos, consulta dados de um contato e sair. • OBS: – A inclusão de contatos deve acontecer na ordem alfabética pelo campo nome. Exercício de Agenda de contatos • Ler e gravar de um arquivo registros de contatos de uma agenda de contatos. Formato do arquivo: – <id>;<tipo (0-geral, 1-cliente ou 2-fornecedor>; <nome>;<telefone>;<email>;<endereço>;<nascimento> – Para o tipo 1: <fidelidade>;<data ultima compra> – Para o tipo 2: <classificação> • Colocar numa lista de contatos. Os contatos podem ser Geral, Cliente ou Fornecedor • Colocar controle das seguintes exceções: – – – – Arquivo não encontrado Tipo de contato inválido (diferente de 0, 1 e 2) Nome deve ter no mínimo duas partículas (nome e sobrenome) Problemas de conversão de String para os respectivos tipos de dados. PARA ENTREGAR ATÉ O GA Lendo e Escrevendo Dados Binários Lendo Bytes e Caracteres Bytes • As classes InputStream e OutputStream, bem como as suas subclasses, são usadas para ler e escrever stream de bytes; Quando usar: para ler e Classes abstratas InputStream – Ler OutputStream - Escrever escrever dados binários, tais como imagens e sons • As classes Reader e Writer (e subclasses) são usadas para ler e escrever streams de caracteres (2 bytes). Caracteres Classes abstratas Reader – Ler Writer - Escrever Quando usar: para ler e escrever dados textuais Leitura Hierarquia de Classes de InpuStream e OutputStream Escrita Serialização Pular para posição no texto A Classe InputStream – abstract class A Classe OutputStream – abstract class BufferedOutputStream FileInputStream e FileOutputStream import java.io.*; public class CopiaArquivo { public static void main(String arg[]) throws IOException { FileInputStream in = new FileInputStream("CopiaArquivo.java"); // sobrescreve arquivo se ele já existe FileOutputStream out = new FileOutputStream ( "Copia de CopiaArquivo.java"); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } FileOutputStream (String name, boolean append) // escreve no final do arquivo } FileOutputStream (File file) FileOutputStream (File file, boolean append) Bufferização • Assim como temos BufferedReader e BufferedWirter para bufferização de arquivos textos, quando estamos trabalhando com arquivos binários, podemos usar as classes: – BufferedInputStream – BufferedOutputStream • Essas classes mantém os dados a serem escritos (no caso da BufferedOutputStream) ou lidos (BufferedOutputStream) em um buffer. Assim, o programa só vai realizar uma nova operação física de entrada ou saída de dados quando o buffer estiver vazio (no caso de leitura) ou cheio (no caso de saída). • Em qualquer momento é possível forçar a saída (a gravação em arquivo) com o método flush( ) da classe BufferedOutputStream. import java.io.*; public class BufferInputOutput { public static void main(String arg[]) { try { FileInputStream in = new FileInputStream("prim.txt"); BufferedInputStream bin = new BufferedInputStream(in); // sobrescreve arquivo se ele já existe FileOutputStream out = new FileOutputStream("Copia.txt"); BufferedOutputStream bout = new BufferedOutputStream(out); int c; while ((c = bin.read()) != -1) bout.write(c); bin.close(); bout.close(); } catch (IOException e) { e.printStackTrace(); } } } Exercícios • Implemente o comando type do MS-DOS. • Voce deve fornecer ao seu programa a seguinte linha de execução: – java Type nomeArquivo • Ele mostrará na tela o conteúdo do arquivo • Antes de tentar abrir o arquivo, teste com a classe File se o arquivo existe, e avise o usuário caso ele não exista PrintStream • Ela grava em formato textual vários tipos de dados do java: boolean, char, int, etc • Não gera exceção IOException • Dados são gravados (flush) automaticamente a cada print • É o tipo da variável System.out. PrintStream import java.io.*; class PrintStreamDemo { public static void main(String args[]){ try { FileOutputStream out = new FileOutputStream("myfile.txt"); PrintStream ps = new PrintStream(out); ps.println ("This data is written to a file:"); System.out.println ("Write successfully"); ps.close(); } } } catch (Exception e){ System.out.println ("Error in writing to file"); } Arquivos de Acesso Randômico Acesso Seqüencial x Acesso aleatório • aceso seqüencial dos dados do arquivo: – programa lê os dados a partir do início do arquivo – lê todos os dados consecutivamente até encontrar dado procurado ou chegar no final do arquivo – Não permite voltar ao início do arquivo para lê-lo novamente: necessário fechar e reabrir o arquivo. – não é possível modificar um dado apenas do arquivo. O arquivo deve ser totalmente sobrescrito. • acesso aleatório dos dados do arquivo: – permite reposicionar ponteiro do arquivo (o número que indica a posição do próximo byte do arquivo a ser lido ou gravado) para voltar ao início do arquivo ou diretamente a uma outra posição. – é possível modificar um dado apenas: interessante exigir que todos os registros tenham o mesmo tamanho Laboratório 2 - Patrícia Jaques 36 Arquivos de acesso randômico import java.io.*; class ArquivoAcessoRandomico { public static void main (String args []) throws java.io.IOException{ RandomAccessFile raf = new RandomAccessFile("Raf.txt","rw"); raf.writeBytes ("Escrevendo a primeira linha.\n"); raf.writeBytes ("Escrevendo a segunda linha.\n"); raf.seek (0); String s = raf.readLine (); System.out.println ("Primeira linha no texto: "+s); raf.seek (raf.length()); // vai para o final do arquivo raf.writeBytes ("Escrevendo a última linha.\n"); } } // se arquivo já existe, substitui a partir da posição 0 Laboratório 2 - Patrícia Jaques 37 RandomAccessFile • Métodos interessantes: – int read () - retorna byte lido como inteiro. Retorna -1 quando chegou no final do arquivo. – void write (int) – grava byte no arquivo – long length ( ) – retorna nro. de bytes no arquivo Serialização Lendo e Escrevendo objetos em arquivos Armazenando objetos em arquivos import java.io.*; class Serializacao { public static void main (String args [ ]) { Pessoa p = new Pessoa ("Homem Aranha", 5, 8, 1937); File f = new File ("ArqSerializacao.arq"); gravaObjeto (f, p); Pessoa p2 = (Pessoa) leObjeto (f); System.out.println ("Foi armazendo o objeto " + " pessoa com os valores:"); System.out.println ("Nome: "+p2.getNome()+" \nData: "+ p2.getData()); } } Armazenando objetos em arquivos private static void gravaObjeto (File f, Object o) { try { FileOutputStream fos = new FileOutputStream (f); ObjectOutputStream os = new ObjectOutputStream (fos); os.writeObject (o); os.close (); } catch (IOException e) { System.out.println ("Erro ao gravar objeto."); } } Armazenando objetos em arquivos private static Object leObjeto (File f) { Object o = null; try { FileInputStream fos = new FileInputStream (f); ObjectInputStream os = new ObjectInputStream (fos); o = os.readObject (); os.close (); }catch (IOException e) { System.out.println ("Erro ao abrir arquivo."); }catch (ClassNotFoundException ce) { System.out.println ("Objeto não encontrado."); } return o; } } // da class Serializacao Armazenando objetos em arquivos class Pessoa implements Serializable { String nome; Data d; public Pessoa (String nome, int dia, int mes, int ano) { this.nome = nome; d = new Data (dia, mes, ano); } public String getNome () { return nome; } public String getData () { return d.getData (); } } // da class Pessoa Armazenando objetos em arquivos class Data implements Serializable{ int dia; int mes; int ano; public Data (int dia, int mes, int ano) { this.dia = dia; this.mes = mes; this.ano = ano; } public String getData (){ return dia+"/"+mes+"/"+ano; } } // da class Data Exercícios • • • • Crie um programa que simule uma base de dados, armazenando registros de produtos em um arquivo. Um registro vai ser um objeto do tipo Book (que implementa a interface Serializable) que vimos no exercício anterior. O seu programa permite ler e armazenar os objetos Book que estão contidos no Vector e que foram lidos do arquivo Books.txt. Voce terá de: – No programa anterior: • • Criar um método que grave todos os objetos que estão dentro de um vector; • Criar método que leia todos os objetos Observação: – O método readObject() não retorna null quando ele atinge o fim do arquivo. Quando chegou no final do arquivo, ele gera uma exceção do tipo java.io.EOFException. – Assim, para ler todos os objetos do arquivo, você tem duas soluções: • Guarde o número de objetos gravados no arquivo numa variável e depois utilize um for para ler os objetos do arquivo. • Trate a exceção EOFException para saber quando chegou no final do arquivo.