21/05/2013 DCC / ICEx / UFMG Informações Complexas Arquivos de Texto e Arquivos Binários Arquivos são usados para gravar informações complexas Arquivo é um grupo de registros relacionados Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo Armazena Informação Hierarquia de Dados Campo Armazena uma sequência de bytes Informação que tem algum significado no domínio do problema (~variável) Julia Registro Formado por vários campos relacionados – campos que merecem ser agrupados Em Java, registro é implementado como uma classe Classificação de Arquivos Existem dois tipos principais de arquivos Arquivos Binários Arquivos de Texto Arquivos binários armazenam registros Mas em Java, dizemos que armazenam objetos serializados Arquivos de texto armazenam caracteres Maria Jose 33 F Julia Souza 27 F Paulo Silva 30 M 27 F Souza 1 Registro Campo Julia 0100 1010 Arquivo Byte J em ASCII Bit Arquivo Binário Um arquivo binário é formado por uma sequência de registros (ou objetos) Todos os registros de um arquivo binário têm a mesma estrutura Um registro é a menor quantidade de informação que pode ser lida ou escrita de um arquivo binário 1 21/05/2013 Arquivos Binários Vantagens Os objetos são mais facilmente gravados e recuperados Gravação é geralmente mais rápida Desvantagens Mais difícil de serem manipulados Somente pode ser lido pelo programa que o gravou Arquivos de Texto Vantagens São de mais fácil manipulação, leitura e escrita Podem ser lidos por diferentes programas (editores de texto) em computadores Desvantagens Difícil recuperar objetos a partir de um arquivo de texto Geralmente mais lentos para leitura e escrita Acesso Sequencial Tanto arquivo de texto quanto arquivos binários são gravados e acessados sequencialmente Arquivos de Texto No arquivo de texto, um caractere é gravado após o outro No arquivo binário, um registro (ou objeto) é gravado após o outro Java vê cada arquivo como um fluxo sequencial de bytes Arquivo de Texto Java não impõe nenhuma estrutura a um arquivo de texto O programador deve estruturar o arquivo para satisfazer os requisitos da aplicação Uma forma simples de estruturar um arquivo de texto é usando a classe Formatter (pacote java.util) Formatar cada linha com os dados Exemplo: CreateTextFile (1) public class CreateTextFile { private Formatter output; Declara um objeto Formater para gravar um arquivo de texto . public void openFile() { try { O nome do arquivo de output = new Formatter( "clients.txt" ); texto quando gravado em } disco será “clients.txt”. catch ( SecurityException securityException ) { System.err.println("You do not have write access to this file."); System.exit( 1 ); } catch ( FileNotFoundException fileNotFoundException ) { System.err.println( "Error opening or creating file." ); System.exit( 1 ); Importante! Se o comando close() não } } for executado, o arquivo não é salvo. public void addRecords() { ... } public void closeFile() { if ( output != null ) output.close(); }} O arquivo só é realmente salvo quando fechado. 2 21/05/2013 Exemplo: CreateTextFile (2) public class CreateTextFile { private Formatter output; public void openFile() { ... } public void addRecords() { Scanner input = new Scanner( System.in ); System.out.println("First name, last name and score."); while ( input.hasNext() ) { try { O usuário deve entrar com três String firstName = input.next(); dados para registro no arquivo: String lastName = input.next(); nome, sobrenome e nota. int score = input.nextInt(); if (score == -1) break; output.format( "%s %s %d \n", firstName, lastName, score); } catch ( FormatterClosedException formatterClosedException ) { ... } catch ( NoSuchElementException elementException ) { ... } System.out.println("First name, last name and score."); } Os dados são armazenados, } um registro por linha. public void closeFile() { ... } } Exemplo: CreateTextFileTest public class CreateTextFileTest { public static void main( String[] args ) { CreateTextFile application = new CreateTextFile(); application.openFile(); application.addRecords(); application.closeFile(); } Adiciona registros (nome, sobrenome e nota) e fecha o arquivo. } Leitura de Arquivo de Texto Os dados armazenados em arquivo de texto podem ser recuperados Cria e abre o arquivo. Note que abrir significa instanciar o objeto Formatter. Exemplo: ReadTextFile (1) public class ReadTextFile { private Scanner input; Declara um objeto Scanner para ler de um arquivo de texto. public void openFile() { Instancia objeto try { Scanner para ler de input = new Scanner( new File( "clients.txt" ) ); um arquivo File. } catch ( FileNotFoundException fileNotFoundException ) { System.err.println( "Error opening file." ); System.exit( 1 ); } } Os dados não estão estruturados e a leitura é sequencial A classe Scanner pode ser utilizada para recuperar dados de um arquivo public void readRecords() { ... } public void closeFile() { if ( input != null ) input.close(); } Ao invés de ler dados do teclado Fecha o objeto Scanner. } Exemplo: ReadTextFile (2) Exemplo: ReadTextFileTest public class ReadTextFile { private Scanner input; public void openFile() { ... } public void readRecords() { System.out.println( "First Name, Last Name and Score" ); try { Enquanto houver dados, lê os while ( input.hasNext() ) { dados do arquivo (nome, sobreString firstName = input.next(); String lastName = input.next(); nome e nota) e imprime na tela. int score = input.nextInt(); System.out.println(firstName + " " + lastName + " " + score); } } catch ( NoSuchElementException elementException ) { ... } catch ( IllegalStateException stateException ) { ... } } public class ReadTextFileTest { Cria um leitor de arquivo de texto e abre o arquivo. public static void main( String[] args ) { ReadTextFile application = new ReadTextFile(); application.openFile(); application.readRecords(); application.closeFile(); } } Lê os registros (nome, sobrenome e nota) do arquivo e o fecha. public void closeFile() { ... } } 3 21/05/2013 Serialização de Objetos Às vezes, queremos gravar um objeto inteiro em disco Arquivos Binários Não apenas informações textuais Para isso, Java fornece um mecanismo chamado serialização Um objeto serializado é representado por uma sequência de bytes Um objeto serializado pode ser gravado e disco e recuperado posteriormente Classes Principais ObjectInputStream Permite que objetos seja lidos do disco Os objetos devem ter sido gravados pela classe ObjectOutputStream Método principal: readObject() Exemplo: StudentScore public class StudentScore implements Serializable { private String firstName = ""; private String lastName = ""; Para ser possível serializar um objeto, ele private int score = 0; deve implementar a interface Serializable. public StudentScore(String first, String last, int score) { setFirstName( first ); A interface Serializable não tem nenhum setLastName( last ); método. Portanto, as classes não setScore( score ); } precisam implementar nenhum método. public void setFirstName( String first ) { firstName = first; } ObjectOutputStream Permite gravar objetos em disco como um fluxo de bytes Método principal: writeObject() Exemplo: CreateSequentialFile public class CreateSequentialFile { private ObjectOutputStream output; Declaração de uma variável ObjectOutputStream que permite escrever o objeto em disco. public void openFile() { try { output = new ObjectOutputStream( new FileOutputStream( "clients.ser" ) ); } catch ( IOException ioException ) { Instanciação do objeto que System.err.println( "Error opening file." ); recebe um FileOutputStream } como parâmetro. } public void addRecords() { ... } public void closeFile() { try { if ( output != null ) output.close(); } catch ( IOException ioException ) { ... } }} O arquivo deve ser fechado para garantir que os dados sejam realmente salvos em disco. public String getFirstName() { return firstName; } public void setLastName( String last ) { lastName = last; } public String getLastName() { return lastName; } public void setScore(int s) { score = s; } public double getScore() { return score; } } Exemplo: método addRecords() public void addRecords() { StudentScore record; int score = -1; Scanner input = new Scanner( System.in ); System.out.println( "First Name, Last Name and Score" ); while ( input.hasNext() ) { try { O usuário entra com String firstName = input.next(); os dados nome, String lastName = input.next(); sobrenome e nota. score = input.nextInt(); if ( score > -1 ) { record = new StudentScore(firstName, lastName, score); output.writeObject( record ); } Um objeto StudentScore é criado e else break; serializado para gravação em disco. } catch ( IOException ioException ) { ... } catch ( NoSuchElementException elementException ) { ... } System.out.println("First name, last name and score."); } } 4 21/05/2013 Exemplo: CreateSequentialFileTest public class CreateSequentialFileTest { public static void main( String[] args ) { Cria o objeto para criador de arquivo binário e abre um arquivo. CreateSequentialFile application = new CreateSequentialFile(); application.openFile(); application.addRecords(); application.closeFile(); } Os registros são armazenados e o arquivo é fechado. } Exemplo: ReadSequentialFile public class ReadSequentialFile { private ObjectInputStream input; Declaração de uma variável ObjectInputStream que permite ler o objeto do disco. public void openFile() { try { input = new ObjectInputStream(new FileInputStream( "clients.ser" )); } catch ( IOException ioException ) { Instanciação do objeto que System.err.println( "Error opening file." ); recebe um FileInputStream } } como parâmetro. public void readRecords() { ... } public void closeFile() { try { if ( input != null ) input.close(); } catch ( IOException ioException ) { ... } }} O arquivo deve ser fechado antes do fim do programa. Exemplo: ReadSequentialFileTest public class ReadSequentialFileTest { Cria o objeto para ler arquivo binário e abre o arquivo. public static void main( String[] args ) { ReadSequentialFile application = new ReadSequentialFile(); application.openFile(); application.readRecords(); application.closeFile(); Desserialização de Objetos Uma vez que um objeto foi serializado, ele pode ser recuperado A recuperação do objeto é chamado desserialização Na verdade, não se recupera exatamente o mesmo objeto serializado, mas um clone do objeto Exemplo: ReadSequentialFile public void readRecords() { StudentScore record; O registro é lido do System.out.println( "First Name, Last Name and Score" ); try { arquivo como objeto. while ( true ) { record = (StudentScore) input.readObject(); System.out.println(record.getFirstName()+" "+record.getLastName()+" "+record.getScore()); } } catch ( EOFException endOfFileException ) { return; } catch ( ClassNotFoundException classNotFoundException ) { System.err.println( "Unable to create object." ); } catch ( IOException ioException ) { System.err.println( "Error during reading from file." ); } } Referências da Aula DEITEL, H. M.; DEITEL P. J. Java: Como Programar, 8a. Edição. Pearson, 2010. Capítulo 17 Arquivos, fluxos e serialização } } Lê os registros armazenados no arquivo e o fecha. 5