ARQUIVO

 

A utilização de arquivos é extremamente importante nos programas, pelo fato de armazenar as informações em dispositivos de armazenamento secundário não-volátil fazendo com que as mesmas não se percam quando o programa é fechado. Isto é uma grande vantagem pelo fato dessas informações poderem ser utilizadas futuramente. Um arquivo é considerado como um recurso de entrada/saída.

 

Java oferece uma série de recursos para manipular arquivos, através do pacote java.io. Todas as operações de um arquivo se fazem através de uma stream de comunicação, que seria como um controle de fluxo de comunicação que é criado para transfêrencia dos dados que são lidos ou gravados. Portanto é necessária a criação desse fluxo para que haja uma correta manipulação de um arquivo.

 

A interação de um programa com um dispositivo através de arquivos passa por três etapas:

 
  • Abertura ou criação de um arquivo;
  • Transferência de dados;
  • Fechamento do arquivo.
 

Em java a classe File permite representar arquivos neste nível de abstração, nos fornecendo diversas informações sobre os arquivos e diretórios nos quais são muito utilizadas com objetos de outras classes java.io para especificar arquivos ou diretórios a manipular.

 

Um exemplo mais específico sobre Arquivos seria uma agenda telefônica, onde os nomes e telefones são guardados como dados, ou seja, depois de escritos esses dados não serão perdidos. Como em Java mesmo após a finalização do programa os dados também serão mantidos.

 
 

O que são Streams?

 

O Java trata a entrada e saída como fluxos de dados (os tão chamados Streams), e, além disso, a abstração criada pela linguagem sobre os Streams é tão grande, que muitas vezes você está puxando/escrevendo dados em algum Stream, e você não sabe se eles estão vindo da internet, de um arquivo texto, ou do usuário que está digitando no console.

 

Um stream é uma sequência ordenada de dados com uma fonte e um destino.

 
 

Java enxerga um arquivo como sendo um fluxo sequencial de bytes. Cada arquivo termina com um marcador de fim de arquivo ou em um número específico de bytes registrado em uma estrutura administrativa do arquivo mantida pelo sistema (descritor do arquivo). Quando um arquivo é aberto, um objeto é criado e um fluxo é associado com o objeto. Três objetos de fluxo são criados automaticamente quando se inicia a execução de um programa Java:

 
  • System.in (objeto de fluxo de entrada padrão) permite que um programa insira bytes via teclado;
  • System.out (objeto de fluxo de entrada) permite a um programa dar saída a dados na tela;
  • System.err (objeto de fluxo de erro) permite a saída de mensagens de erros na tela.
 
Classe File
 

Usada para representar o sistema de arquivos, é apenas uma abstração - a existência de um objeto File não significa a existência de um arquivo ou diretório.

 

Contém métodos para testar a existência de arquivos, para definir permissões (nos S.O.s onde for aplicável), para apagar arquivos, criar diretórios, listar o conteúdo de diretórios, etc.

 

Alguns exemplos de métodos:

 
public String getParent();         // retorna o diretório (objeto File) pai
public list();        // retorna lista de arquivos contidos no diretório byte
public boolean isFile();       // retorna se é um arquivo
public boolean isDirectory();        // retorna se é um diretório long
public boolean delete();        // tenta apagar o diretório ou arquivo byte
public long length();       // retorna o tamanho do arquivo em bytes
public boolean mkdir();       // cria um diretório com o nome do arquivo
public String getAbsolutePath();        // retorna o caminho absoluto (path)

 

Para processamento de arquivos em Java, o pacote java.io deve ser importado. As classes InputStream e OutputStream (ambas derivadas de Object e definida como abstract) são as classes fundamentais que definem métodos para realização de entrada e saída de BYTES respectivamente.

 
A classe InputStream
 

InputStream é uma classe abstrata que contém os métodos básicos para leitura de bytes de dados de um stream. Embora InputStream seja uma classe abstract muitos dos seus métodos somente especificam o retorno de InputStream, dessa forma trabalha-se diretamente com eles.

 

O programa a seguir lê o conteúdo de um arquivo através da utilização da classe FileInputStream.

 
/**
* Síntese
*   Objetivo: Ler o conteúdo em bytes do arquivo Teste.txt pela
*   		  classe FileInputStream
*   Entrada: Nenhuma
*   Saída: Conteúdo do arquivo Teste.txt
*/

import java.io.FileInputStream;    // importação da classe FileInputStream
import java.io.FileNotFoundException; // importação FileNotFoundException
import java.io.IOException; // importação da classe IOException

public class ExemploInputStream {
    
    public static void main(String[] args) {
    
        try {
        
            FileInputStream leitura = new FileInputStream("Teste.txt");
            
            byte [] conteudoByte = new byte[leitura.available()];
            
            leitura.read(conteudoByte);
            
            String conteudoStr = new String(conteudoByte);
            
            leitura.close();
            
            System.out.println(conteudoStr);
            
        } catch (FileNotFoundException e) {
        
            System.out.println("Arquivo não encontrado!");
            
        } catch (IOException e) {
        
  	        System.out.println("Erro ao manipular arquivo!");
        
        }
    
    }

}

 

Considere que o arquivo Texte.txt possui a seguinte frase escrita: "Meu arquivo Teste.txt funcionou!". A execução do programa anterior apresentaria a saída de dados na console como representado na figura a seguir:

 
 
A Classe OutputStream
 

OutputStream envia uma série de bytes de dados para um alvo tal como o console ou para um network server. Tal como InputStream, OutputStream é uma classe abstrata porém com métodos originalmente úteis, como os exemplos a seguir.

 

O método write() envia filas de bytes de dados para quem estiver "ouvindo" o fluxo. Muitas vezes os outputStreams são buffered para melhorar a performance, ou seja, ao invés de escrever byte a byte, eles são acumulados em um buffer de tamanho que varia de alguns a um monte de bytes. Então, quando o buffer se torna cheio, todos os dados são escritos de uma única vez.

 

O método flush() força que o dado seja escrito mesmo que o buffer não esteja ainda cheio. Observar que não se trata de bufferização realizada por um objeto BufferedOutputStream. Aquela bufferização é manipulada por Java runtime. Esta bufferização é a nível de SO nativo. De qualquer maneira, a chamada de um método flush() deverá esvaziar ambos os buffers.

 

O método close() fecha o stream e libera qualquer recurso associado com ele. A tentativa de escrever ou ler um stream fechado lança um IOException.

 

O programa a seguir escreve no arquivo o conteúdo informado.

 
/**
* Síntese
*   Objetivo: Escrever um conteúdo informado no arquivo Teste.txt
*   Entrada: Conteúdo a ser gravado no arquivo
*    Saída: Resultado de sucesso ou não
*/

import java.io.FileOutputStream;     // importação da classe FileOutputStream
import java.io.FileNotFoundException;     // importação FileNotFoundException
import java.io.IOException;     // importação da classe IOException
import java.util.Scanner;     // importação da classe Scanner

public class ExemploOutputStream {
    
    public static void main(String[] args) {
    
        Scanner leitura = new Scanner(System.in);
        
        try {
        
            FileOutputStream escrita = new FileOutputStream("Teste.txt");
            
            System.out.println("Informe o conteudo a ser gravado: ");
            
            String str = leitura.nextLine();
            
            byte[] conteudo = str.getBytes();
            
            escrita.write(conteudo);
            
            System.out.println("Operação Realizada com Sucesso");
            
        } catch (FileNotFoundException e) {
        
	        System.out.println("Arquivo não encontrado!");
        
        } catch (IOException e) {
        
    	    System.out.println("Erro ao manipular arquivo");
        
        }
    
    }

}

 

A execução do programa anterior é representada na figura a seguir:

 
 

Os arquivos são abertos criando-se objetos destas classes de fluxo que herdam de InputStream, OutputStream, Reader, Writer como pode ser visto na figura.

 
 

As classes abaixo oferecem pelo menos um construtor que recebe como argumento um objeto da classe File e implementam os métodos básicos de transferência de dados. InputStreamReader é um filtro que converte bytes em chars.

 
 

A maneira mais eficiente de ler um arquivo de texto é usar FileReader com um BufferedReader. Para gravar, use um FileWriter com um PrintWriter.

 
ClassRandomAccessFile
 

Construindo uma instância do RandomAccessFile, você pode procurar por qualquer posição desejada dentro de um arquivo, e então ler ou escrever um montante de dados desejados.

 

Construindo uma instância do RandomAccessFile no modo "r", se o arquivo não existir dispara uma exceção "FileNotFoundException". Construindo uma instância do RandomAccessFile no modo 'rw', se o arquivo não existir um arquivo de tamanho zero é criado.

 

Exemplo Class RandomAccessFile - leitura:

 
/**
* Síntese
*   Objetivo: Ler o arquivo Alunos.txt e imprimir na console
*   Entrada: sem entrada
*   Saída: Listar os nomes que estao no arquivo Alunos.txt na console
*/

import java.io.File;     // importação da classe File
import java.io.IOException;     // importação da classe IOException
importjava.io.RandomAccessFile; // importação da classe RandomAccessFile;

class RandomAccessFileDemo {

    public static void main(String[]args) throws IOException {  

        File fileName = new File("C:\\Alunos.txt");
        
        RandomAccessFile obj = new RandomAccessFile(fileName , "rw");
        
        String result = null;
        
        int i=0;       
         
        
        while(i<obj.length()){
            
            result=obj.readLine();
            
            if(result==null){
            
            	break;
            
        	}
            
            System.out.println(result);
            
            i++;
            
        }
        
    }

}

 

A representação da execução do programa anterior na console seria como está na figura a seguir:

 
 

Exemplo Class RandomAccessFile - gravação:

 
/**
* Síntese
*   Objetivo: Gravar no arquivo Alunos2.txt tudo que for digitado
*   		no teclado enquanto nao for digitado a palavra "fim"
*   Entrada: Tudo que for digitado
*   		Saída: Salvar no arquivo Alunos2.txt os dados digitados em forma
*   		de bytes
*/

import java.io.File;     // importação da classe File
import java.io.IOException;     // importação da classe IOException
importjava.io.RandomAccessFile; // importação da classe RandomAccessFile;
import java.io.BufferedReader; // importação da classe BufferedReader;
import java.io.InputStreamReader; // importação classe InputStreamReader;

class RandomAccessFileDemo {

   public static void main(String[]args) throws IOException {  

        File fileName = new File("c:\\Alunos2.txt");
        
        RandomAccessFile obj = new RandomAccessFile(fileName , "rw");
        
        InputStreamReader conversor = new InputStreamReader(System.in);
        
        BufferedReader bf = new BufferedReader(conversor);
        
        String result = null;
        
        int i=0;
        
        boolean continua=true;
        
        String linha;
        
                 
        while(continua){
        
            linha = bf.readLine();
            
            if (linha.equals("fim")){
            
            	continua=false;
            
            }else{
            
            	obj.writeBytes(linha+"\n");
            
            }
        
        }
        
        obj.close();
        
   }

}

 

Esse programa não possui uma representação pois ele insere dados através da console.

 
Serialização de objetos
 

Java permite a gravação direta de objetos em disco ou seu envio através da rede. Neste caso o objeto deve implementar java.io.Serializable.

 

Um objeto que implementa a interface Serializable poderá ser gravado em qualquer stream usando o método writeObject() de ObjectOutputStream e poderá ser recuperado de qualquer stream usando o método readObject() de ObjectInputStream.

 

Trechos de códigos dos métodos da Interface Serializable:

 
/**
* Síntese
*   Objetivo: Gravar os objetos criados no arquivo usando os metodos
*   da interface serializable
*/

Aluno a = new Aluno("Pimenta");

Aluno b = new Aluno("Camilo");

File arquivo = new File("c:\\GuardaObjetos.txt");

FileOutputStream fOut = new FileOutputStream(arquivo);

ObjectOutputStream objOut = new ObjectOutputStream(fOut);

objOut.writeObject(a);

objOut.writeObject(b);

/**
* Síntese
*   Objetivo: Ler os objetos que estao gravados no arquivo utilizando
*   os metodos da interface
*/

FileInputStream file = new FileInputStream(arquivo);

ObjectInputStream objIn = new ObjectInputStream(file);

Aluno primeiro=(Aluno)objIn.readObject();

System.out.println(primeiro.getNome());

Aluno segundo=(Aluno)objIn.readObject();

System.out.println(segundo.getNome()); 

 

Atividade de Fixação

 

No intuito de fixar a aprendizagem iniciada por meio deste módulo e verificar como seu entendimento sobre este conteúdo está, estão sendo sugeridos alguns exercícios de fixação para serem resolvidos. Clique no link de exercícios ao lado, pois será por meio dele iniciada a lista de exercícios sobre os conteúdos estudados até este momento nesta disciplina.