![]() |
|
Introdução
Os meios de armazenamento persistentes são fatores importantes na visa de um computador, já que a memória eletrônica é apagada quando ele é desligado. Caso não existissem, teriamos de resscrever dados de configuração, nomes, textos, entre outras coisas.
O uso de mecanismo de leitura e escrita eleva a outro nível o poder de uma aplicação. Em uma maneira mais simples, permite que guardemos dados para uso posterior, que mantenhamos configurações de um dado programa ou que possamos ler um arquivo de terceiros ou gerar arquivos com os dados trabalhados até o momento.
O foco deste tutorial será apresentar formas de ler e gravar dados em arquivos utilizando pacote java.io. Nesse pacote, encontramos classes que permitem interagir com o sistema de arquivos e realizar tarefas de leitura e escrita.
A classe File é a classe do Java que mermite ter acesso às informações sobre o sistema de arquivos: nome, diretório, tamanho, permissões de escrita e leitura e outroas coisas mais.
Como exemplo, um arquivo em disco de nome MeuTexto.txt, como mostra a seguir:
Este é um arquivo texto simples.
Segunda linha.
Terceira linha.
Fim.
Para obeter informaçõe sobre este arquivo, observe o código da classe UsoDoFile.java a seguir:
import java.io.File;
import javax.swing.JOptionPane;
public class UsoDoFile {
public static void main(String[] args) {
String var = "";
File arquivo = new File("MeuTexto.txt");
var = "Nome: " + arquivo.getName() + "\n\r";
var += "Caminho: " + arquivo.getAbsolutePath() + "\n\r";
var += "Existe? " + arquivo.exists() + "\n\r";
var += "É um diretório? " + arquivo.isDirectory() + "\n\r";
var += "É um arquivo? " + arquivo.isFile() + "\n\r";
var += "Pode ser lido? " + arquivo.canRead() + "\n\r";
var += "Pode ser escrito? " + arquivo.canWrite() + "\n\r";
JOptionPane.showMessageDialog( null, var, "Informacao do Sistema", JOptionPane.INFORMATION_MESSAGE );
}
}
Para o funcionamento deste programa, há necessidade que os arquivos MeuTexto.txt e UsoDoFile.java estejam no mesmo diretório .
A classe File é ainda uma representação para arquivos e diretórios de sistema, trazendo informações adicionais sobre o sistema operacional, tais como qual caractere é separador de diretório, informações sobre discos disponíveis, etc.
Em Java, a classe File permite representar arquivos nesse nível de abstração. Um dos construtores desta classe recebe como argumento uma string que pode identificar, por exemplo, o nome de um arquivo em disco. Os métodos desta classe permitem obter informações sobre o arquivo -- por exemplo, exists(), canRead(), canWrite(), length() e lastModified() -- e realizar operações sobre o arquivo como um todo, como em delete() e deleteOnExit().
Para compreender as funcionalidade, observe o código da classe "InformacaoSistema.java" a seguir:
import java.io.File;
import javax.swing.JOptionPane;
public class InformacaoSistema {
public static void main(String[] args) {
String var = "";
var = "Separador de Path: " + File.pathSeparator + "\n\r";
var += "Separador de Diretório: " + File.separator + "\n\r";
File discos [] = File.listRoots();
for (int cont=0; cont<discos.length; cont++) {
var += "Disco " + cont + ": " + discos[cont] + "\n\r";
}
JOptionPane.showMessageDialog( null, var, "Informacao do Sistema", JOptionPane.INFORMATION_MESSAGE );
}
}
O programa obtem informações sobre o sistema operacional, o separador de variável de sistema path(caminho de atalho) e o separador para diretórios.
Também é obtido através do programa, uma lista de discos existente localmente atravésdo método listRoots(), no caso do sistema Windows, ele retorna o nome (letras) dos drives lógicos existente. A seguir observe o resultado da execução do programa:
No computador que esta sendo executado com sistema operacional Windows, onde o separador de path é o ponto e virgula(;) e o separador de diretório é a barra invertida (\). Ale disso, o computador de execução possuia um drive de disquete (A:\).
A classe File representa o sistema de arquivos e seus objetos são as referências a arquivos e diretórios, existentes ou não. A referência aos arquivos é bastante útil para obtermos informações relevantes como:
De forma genérica, havendo um dispositivo de entrada de dados habilitado, o programa obtém dados deste dispositivo através de uma operação read(). Similarmente, um dado pode ser enviado para um dispositivo de saída habilitado através de uma operação write().

Na linguagem Java, arquivos são considerados fonte, quando realizamos a leitura a partir dele; e destino, quando realizamos a escrita nele. Ao fazermos uma leitura, os dados partem da fonte e trafegam ordenados unidade a unidade até o programa ou classe Java. Da mesma forma, quando fazemos uma gravação, o programa envia os dados ordenado, unidade a unidade, para um destino.
Fontes de dados manipuladas como seqüências de bytes são tratadas em Java pela classe InputStream e suas classes derivadas.
As principais subclasses de InputStream, já
oferecidas como parte do pacote java.io, são:
java.io.ByteArrayInputStream
Valores
são originários de um arranjo de bytes;
java.io.FileInputStream
Bytes
são
originários de um arquivo; usualmente, usado em conjunto com
BufferedInputStream e DataInputStream;
java.io.FilterInputStream
Oferece
as
definições necessárias para filtrar
dados de um
InputStream. Útil através de alguma de suas
classes
derivadas:
java.io.BufferedInputStream
Lê transparentemente
grandes volumes de bytes, armazenando-os em um buffer interno,
melhorando a eficiência de operação
para fontes de
dados lentas;
java.io.DataInputStream
Permite a leitura de
representações binárias dos tipos
primitivos de
Java, oferecendo métodos tais como readBoolean(),
readChar(),
readDouble e readInt(). É uma
implementação da
interface DataInput.
java.io.PushbackInputStream
Oferece métodos
unread() que permitem repor um ou mais bytes de volta à sua
fonte, como se eles não tivessem sido lidos;
java.io.ObjectInputStream
Oferece método readObject()
para a leitura de
objetos que foram serializados para um ObjectOutputStream;
java.io.PipedInputStream
Oferece a funcionalidade de leitura de
um pipe de
bytes cuja origem está associada a um objeto
PipedOutputStream;
java.io.SequenceInputStream
Oferece a funcionalidade para concatenar
dois ou
mais objetos InputStream; o construtor especifica os objetos que
serão concatenados e, automaticamente, quando o fim do
primeiro
objeto é alcançado os bytes passam a ser obtidos
do
segundo objeto.
Isso é realizado porque não é possível transferir tudo ao mesmo tempo, entre a memória do programa e o arquivo, ou ler do arquivo para memória instantaneamente.
Arquivos binários são aqueles que usam todo o conjunto de números para representar uma informação, por exemplo, uma foto, uma planilha, um arquivo executável.
Existe ainda os arquivos contendo apenas caracteres, ou seja, letras, números e alguns caracteres especiais para representar algo na tela ou na impressora. Esses arquivos não precisam de todos os números possíveis para representar suas informações. Sendo assim, eles sãi um caso especial e podem ser trabalhados mais facilmente caractere a caractere, ao invés de número a número. A esses arquivos, damos o nome de arquivo-texto.
Saídas de seqüências de bytes são tratadas por OutputStream e suas classes derivadas.
3. OutputStream As
principais subclasses de OutputStream no pacote java.io
são:
java.io.ByteArrayOutputStream
Facilidades para escrever para um
arranjo de bytes interno, que cresce de acordo com a necessidade e pode
ser acessado posteriormente através do método
toByteArray() ou toString();
java.io.FileOutputStream
Facilidades para escrever em
arquivos, usualmente utilizadas em conjunção com
as
classes BufferedOutputStream e DataOutputStream;
java.io.FilterOutputStream
Definição de
funcionalidades básicas para a filtragem de saída
de
dados, implementadas em alguma de suas classes derivadas:
java.io.BufferedOutputStream
Armazena bytes em um buffer
interno até que o buffer esteja cheio ou o método
flush()
seja invocado;
java.io.DataOutputStream
Permite escrever valores de
variáveis de tipos primitivos de Java em um formato
binário portátil. É uma
implementação da interface DataOutput.;
java.io.PrintStream
Oferece métodos para
apresentar representações textuais dos valores de
tipos
primitivos Java, através de métodos print() e
println();
java.io.ObjectOutputStream
Permite armazenar a
representação de um objeto
serializável em um
OutputStream;
java.io.PipedOutputStream
Implementa a origem de um
pipe de bytes, que serão lidos a partir de um objeto
PipedInputStream.
4. Exemplo das classes Reader e Writer
Observe que as funcionalidades de transferência seqüencial de dados a partir de ou para um arquivo não é suportada pela classe File, mas sim pelas classes FileInputStream, FileOutputStream, FileReader e FileWriter. Todas estas classes 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 suportados respectivamente por InputStream, OutputStream, Reader e Writer.
Observe os código a seguir:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Leitor {
public static String ler(File arquivo) {
StringBuffer sb = new StringBuffer();
try {
FileReader reader = new FileReader(arquivo);
int c;
do {
c = reader.read();
if (c!=-1) {
sb.append( (char)c );
}
} while (c != -1);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
import java.io.File;
import javax.swing.JOptionPane;
public class UsoLeitor {
public static void main(String[] args) {
File arquivo = new File("MeuTexto.txt");
String s = Leitor.ler(arquivo);
JOptionPane.showMessageDialog( null, s, "Uso Leitor", JOptionPane.INFORMATION_MESSAGE );
}
}
O programa é executado através da classe UsoLeitor.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Escritor {
public static void escreve(File arquivo, String texto) {
try {
FileWriter writer = new FileWriter(arquivo);
char [] c = texto.toCharArray();
for (int cont=0; cont<c.length; cont++) {
writer.write(c[cont]);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
O método estático contido na classe Escritor, recebe uma referência ao arquivo e um texto a ser gravado.
import java.io.File;
import javax.swing.JOptionPane;
public class UsoEscritor {
public static void main(String[] args) {
String nome_arquivo = JOptionPane.showInputDialog("Entre com o nome do arquivo");
File arquivo = new File(nome_arquivo);
String texto = JOptionPane.showInputDialog("Entre com um texto pequeno");
Escritor.escreve(arquivo, texto);
}
}
O exemplo a seguir demonstra como podemos realizar cópias de arquivos, utilizando uma classe File do Java.
import java.io.File;
import javax.swing.JOptionPane;
public class Copiador {
public static void main(String[] args) {
String arquivo1 = JOptionPane.showInputDialog("Entre com o nome do arquivo a ser copiado");
File entrada = new File(arquivo1);
String arquivo2 = JOptionPane.showInputDialog("Entre com o nome do arquivo copiado");
File saida = new File(arquivo2);
String s = Leitor.ler(entrada);
Escritor.escreve(saida, s);
}
}
A classe Copiador, atende bem
ao
propósito de leitura de arquivos textos e cópia
dos
mesmos. O problema é que não
funcionará para um
arquivo binário, como uma imagem, por exemplo.
Arquivos binários possuem uma variedade de valores binários, que um arquivo texto não possui.
Neste caso, será necessário um programa que leia arquivos binários e não caracteres, como també, escrever arquivos binários em disco. Veja o exemplo a seguir:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopiadorBinario {
public static void copia(File entrada, File saida) {
try {
FileInputStream input = new FileInputStream(entrada);
FileOutputStream output = new FileOutputStream(saida);
int c;
do {
c = input.read();
if (c!=-1) {
output.write(c);
}
} while (c != -1);
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
O programa contido na classe UsoCopiadorBinario, utiliza a classe CopiadorBinario como mostra o código a seguir:
import java.io.File;
import javax.swing.JOptionPane;
public class UsoCopiadorBinario {
public static void main(String[] args) {
String arquivo = JOptionPane.showInputDialog("Entre com o nome do arquivo a ser copiado");
File entrada = new File(arquivo);
String arquivo_saida = JOptionPane.showInputDialog("Entre com o nome da copia do arquivo");
File saida = new File(arquivo_saida);
CopiadorBinario.copia(entrada, saida);
JOptionPane.showMessageDialog( null, "Cópia concluida", "Copia", JOptionPane.INFORMATION_MESSAGE );
}
}
Essencialmente, um buffer é uma entidade intermediária entre duas ou mais outras entidades que produzem e consomem elementos. Internamente, um buffer contém uma área de memória que é utilizada para armazenamento temporário de elementos que foram produzidos mas ainda não foram consumidos.

Essa capacidade de um buffer manter temporariamente parte dos dados produzidos mas não consumidos torna-o um mecanismo adequado para compatibilizar a operação de entidades operando em diferentes velocidades. Além de oferecer transparentemente as mesmas funcionalidades de leitura e escrita de dados, um buffer normalmente oferece operações adicionais que permitem consultar se há dados disponíveis para leitura no buffer de entrada ou para solicitar que os dados presentes no buffer de saída sejam enviados imediatamente para o dispositivo de saída.
Em Java, há quatro classes que adicionam as funcionalidades de buffering às classes fundamentais de entrada e saída. Para classes que manipulam bytes, as classes BufferedInputStream e BufferedOutputStream são oferecidas. Para a manipulação de entrada e saída de texto, as classes BufferedReader e BufferedWriter.
Observe a seguir o programa demonstrando BufferedReader e BufferedWrite:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class LeitorBuffer {
public static String ler(File arquivo) {
StringBuffer sb = new StringBuffer();
try {
FileReader reader = new FileReader(arquivo);
BufferedReader bufReader = new BufferedReader(reader);
String s;
do {
s = bufReader.readLine();
if (s!=null) {
sb.append( s + "\r\n" );
}
} while (s!=null);
bufReader.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class EscritorBuffer {
public static void escreve(File arquivo, String texto) {
try {
FileWriter writer = new FileWriter(arquivo);
BufferedWriter bufWriter = new BufferedWriter(writer);
bufWriter.write(texto);
bufWriter.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.File;
import javax.swing.JOptionPane;
public class CopiadorBuffer {
public static void main(String[] args) {
String arquivo_entrada = JOptionPane.showInputDialog("Entre com o nome do arquivo de entrada");
File entrada = new File(arquivo_entrada);
String arquivo_saida = JOptionPane.showInputDialog("Entre com o nome do arquivo de saida");
File saida = new File(arquivo_saida);
String s = LeitorBuffer.ler(entrada);
EscritorBuffer.escreve(saida, s);
}
}
import java.awt.Container;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class LeitorSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("Javanoroeste");
JTextArea textArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textArea);
Container container = frame.getContentPane();
container.add(scrollPane);
frame.setSize(500, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
String arquivo_ler = JOptionPane.showInputDialog("Entre com o nome do arquivo de saida");
File arquivo = new File(arquivo_ler);
String s = LeitorBuffer.ler(arquivo);
textArea.append ( s );
}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class LeitorSwingComplexo {
private static JTextArea textArea;
private static JFrame frame;
public static void main(String[] args) {
frame = new JFrame("Javanoroeste");
JPanel p = new JPanel(new BorderLayout());
textArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textArea);
p.add(scrollPane, BorderLayout.CENTER);
JButton button = new JButton("Abrir Arquivo");
button.addActionListener(new AcaoLeitura());
p.add(button, BorderLayout.SOUTH);
Container container = frame.getContentPane();
container.add(p);
frame.setSize(500, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
static class AcaoLeitura implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
JFileChooser fileChooser = new JFileChooser(".");
fileChooser.showOpenDialog(frame);
File arquivo = fileChooser.getSelectedFile();
if (arquivo!=null) {
textArea.setText("");
String s = LeitorBuffer.ler(arquivo);
textArea.append ( s );
}
}
}
}
Autores: Carlos Fernando Gonçalves e Marli Esprega Gonçalves (Antares Information Systems)