Aula Persistência 01 (Java)

78
UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO ALGORITMOS E PROGRAMAÇÃO II – 2014.2 Fábio M. Pereira ([email protected])

description

Aula Algoritmos e Programação II - Persistência 01 (Arquivos Java)

Transcript of Aula Persistência 01 (Java)

Page 1: Aula Persistência 01 (Java)

UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO

ALGORITMOS E PROGRAMAÇÃO II – 2014.2

Fábio M. Pereira

([email protected])

Page 2: Aula Persistência 01 (Java)

Roteiro

• Fluxo de E/S

– Byte streams

– Streams de caracteres

– E/S orientada a linha

– Buffered streams

– E/S a partir da linha de comando

– Streams de dados

– Streams de objetos

– Entrada e saída de objetos complexos

• E/S em arquivo

– Objetos File

– Arquivos de acesso aleatório

Page 3: Aula Persistência 01 (Java)
Page 4: Aula Persistência 01 (Java)

Fluxo de E/S

• Um fluxo de E/S (entrada/saída – I/O stream) representa uma fonte de entrada ou um destino de saída

• Um fluxo pode representar muitos tipos diferentes de origens e destinos, incluindo arquivos em disco, dispositivos, outros programas, e matrizes de memória

• Streams dão suporte a muitos tipos diferentes de dados, incluindo bytes simples, tipos de dados primitivos, caracteres localizados e objetos

• Alguns streams simplesmente passam os dados, outros manipulam e transformam os dados de maneira útil

Page 5: Aula Persistência 01 (Java)

Fluxo de E/S

• Não importa como eles funcionam internamente, todos os streams apresentam o mesmo modelo simples aos programas que as utilizam: um stream é uma sequência de dados

• Um programa usa um fluxo de entrada para ler os dados a partir de uma fonte, um item de cada vez:

Page 6: Aula Persistência 01 (Java)

Fluxo de E/S

• Um programa usa um fluxo de saída para escrever dados para um destino, um item de cada vez:

• O destino fonte de dados e os dados apresentados na figura pode ser qualquer coisa que mantém, gera, ou consome dados

• Obviamente, isso inclui arquivos do disco, mas a origem ou destino pode também ser outro programa, um dispositivo periférico, um socket de rede, ou um array

Page 7: Aula Persistência 01 (Java)

Byte streams

• Vamos usar o tipo mais básico de fluxo, byte stream, para demonstrar as operações comuns do fluxo de E/S

• Como exemplo de entrada, vamos usar o arquivo xanadu.txt, que contém o seguinte verso:

In Xanadu did Kubla Khan

A stately pleasure-dome decree:

Where Alph, the sacred river, ran

Through caverns measureless to man

Down to a sunless sea.

Page 8: Aula Persistência 01 (Java)

Byte streams

• Programas usam fluxos de bytes para realizar a entrada e saída de bytes de 8 bits

• Todas as classes de fluxo de bytes são descendentes de InputStream e OutputStream

• Existem muitas classes de fluxo de bytes

• Para demonstrar como streams funcionam, vamos nos concentrar nos arquivos de E/S de fluxos de bytes, FileInputStream e FileOutputStream

• Outros tipos de fluxos de bytes são utilizados da mesma maneira, eles diferem principalmente na forma como eles são construídos

Page 9: Aula Persistência 01 (Java)

Utilizando byte streams

• Programa CopyBytes, que utiliza byte streams para copiar xanadu.txt:

Page 10: Aula Persistência 01 (Java)

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class CopyBytes {

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

FileInputStream in = null;

FileOutputStream out = null;

try {

in = new FileInputStream("xanadu.txt");

out = new FileOutputStream("copiaxanadu.txt");

int b;

while ((b = in.read()) != -1) {

out.write(b);

}

} finally {

if (in != null) {

in.close();

}

if (out != null) {

out.close();

}

}

}

}

Page 11: Aula Persistência 01 (Java)

Utilizando byte streams

• CopyBytes passa a maior parte de seu tempo em um laço simples que lê o fluxo de entrada e escreve no fluxo de saída, um byte de cada vez:

Page 12: Aula Persistência 01 (Java)

Utilizando byte streams

• Observe que read() retorna um valor int

• Se a entrada é um fluxo de bytes, por que read() não retorna um valor byte?

– Usando um int como um tipo de retorno permite que read() use -1 para indicar que ele tenha atingido o fim do stream

• Fechar um stream, quando ele não é mais necessário é muito importante, tão importante que CopyBytes usa um bloco finally para garantir que ambos os streams serão fechados, mesmo se ocorrer um erro

• Essa prática ajuda a evitar falha de recursos

Page 13: Aula Persistência 01 (Java)

Utilizando byte streams

• CopyBytes parece ser um programa normal, mas, na verdade, representa uma espécie de baixo-nível de E/S, que devemos evitar

• Uma vez que xanadu.txt contém dados de caracteres, a melhor abordagem é a utilização de streams de caracteres

• Há também streams para tipos de dados mais complexos

• Fluxos de bytes só devem ser usados para E/S mais primitivas

Page 14: Aula Persistência 01 (Java)

Streams de caracteres

• A plataforma Java armazena valores de caracteres usando convenções Unicode

– Fluxos de E/S de caracteres automaticamente traduzem este formato interno de e para o conjunto de caracteres local

– Em localidades ocidentais, o conjunto de caracteres local é geralmente um super-conjunto de ASCII de 8 bits

• Para a maioria das aplicações, E/S com fluxos de caracteres não é mais complicado do que E/S com fluxos de bytes

• Entrada e saída feito com classes stream que convertem automaticamente de e para o conjunto de caracteres local

Page 15: Aula Persistência 01 (Java)

Streams de caracteres

• Um programa que utiliza fluxos de caracteres no lugar de fluxos de byte automaticamente adapta-se ao caráter local definido e está pronto para internacionalização sem esforço extra pelo programador

• Se internacionalização não é uma prioridade, podemos simplesmente usar as classes de fluxo de caracteres sem prestar muita atenção às questões de conjuntos de caracteres

• Posteriormente, se internacionalização tornar-se uma prioridade, o programa pode ser adaptado sem extensa recodificação

Page 16: Aula Persistência 01 (Java)

Usando streams de caracteres

• Todas as classes de fluxo de caracteres são descendentes de Reader e Writer

• Tal como acontece com fluxos de bytes, há classes de fluxo de caracteres que se especializam em arquivo de E/S: FileReader e FileWriter

• O exemplo CopyCharacters ilustra essas classes:

Page 17: Aula Persistência 01 (Java)

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

public class CopyCharacters {

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

FileReader in = null;

FileWriter out = null;

try {

in = new FileReader("xanadu.txt");

out = new FileWriter("copiaxanadu.txt");

int c;

while ((c = in.read()) != -1) {

out.write(c);

}

} finally {

if (in != null) {

in.close();

}

if (out != null) {

out.close();

}

}

}

}

Page 18: Aula Persistência 01 (Java)

Usando streams de caracteres

• CopyCharacters é muito semelhante ao CopyBytes

• A diferença mais importante é que CopyCharacters usa FileReader e FileWriter para entrada e saída no lugar de FileInputStream e FileOutputStream

• Note que ambos usam uma variável int para leitura e escrita, no entanto, em CopyCharacters, a variável int

detém um valor de caractere em seus últimos 16 bits, em CopyBytes, a variável int detém um valor byte em seus últimos 8 bits

Page 19: Aula Persistência 01 (Java)

E/S orientada a linha

• E/S de caracteres ocorre geralmente em unidades maiores do que os caracteres individuais

• Uma unidade comum é a linha: uma sequência de caracteres com um terminador de linha no final

• Um terminador de linha pode ser uma sequência de retorno de carro/avanço de linha ("\r \n"), um único retorno de carro ("\r"), ou um único avanço de linha ("\n")

• Dar suporte a todas os possíveis terminadores de linha permite que os programas leiam arquivos de texto criados em qualquer um dos sistemas operacionais existentes

Page 20: Aula Persistência 01 (Java)

E/S orientada a linha

• Vamos modificar o exemplo CopyCharacters para usar E/S orientada a linha

• Para fazer isso, temos que usar duas classes que não vimos antes, BufferedReader e PrintWriter

Page 21: Aula Persistência 01 (Java)

import java.io.FileReader;

import java.io.FileWriter;

import java.io.BufferedReader;

import java.io.PrintWriter;

import java.io.IOException;

public class CopyLines {

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

BufferedReader in = null;

PrintWriter out = null;

try {

in = new BufferedReader(new FileReader("xanadu.txt"));

out = new PrintWriter(new FileWriter("copiaxanadu.txt"));

String l;

while ((l = in.readLine()) != null) {

out.println(l);

}

} finally {

if (in != null) {

in.close();

}

if (out != null) {

out.close();

}

}

}

}

Page 22: Aula Persistência 01 (Java)

Buffered streams

• A maioria dos exemplos que vimos até agora usam E/S sem buffer

• Isso significa que cada pedido de leitura ou escrita é tratado diretamente pelo sistema operacional, o que pode tornar um programa muito menos eficiente, uma vez que cada um desses pedidos, muitas vezes desencadeia acesso ao disco, a atividade de rede, ou alguma outra operação que é relativamente cara

• Para reduzir esse tipo de sobrecarga, a plataforma Java implementa E/S com buffer – Fluxos com buffer de entrada leem dados a partir de uma área de

memória conhecida como buffer, a API nativa de entrada é chamada apenas quando o buffer está vazio

– Da mesma forma, fluxos de saída em buffer gravam dados em um buffer, e a API de saída nativa é chamada apenas quando o buffer está cheio

Page 23: Aula Persistência 01 (Java)

Buffered streams

• Um programa pode converter um fluxo sem buffer em um fluxo com buffer usando a expressão de conversão que utilizamos várias vezes, onde o objeto de fluxo sem buffer é passado para o construtor de uma classe de stream com buffer

• Vejamos como podemos modificar as chamadas do construtor no exemplo CopyCharacters para usar E/S com buffer: in = new BufferedReader(new

FileReader("xanadu.txt"));

out = new BufferedWriter(new

FileWriter("copiaxanadu.txt"));

Page 24: Aula Persistência 01 (Java)

Descarregando buffered streams

• Muitas vezes faz sentido descarregar um buffer em pontos críticos, sem esperar que ele seja preenchido

• Isto é conhecido como flushing the buffer

• Algumas classes buffer de saída dão suporte a autoflush, especificado por um argumento opcional do construtor

• Quando o autoflush está habilitado, certos eventos-chave fazem com que o buffer seja liberado

• Por exemplo, um objeto autoflush PrintWriter libera o buffer a cada invocação de println ou format

• Para liberar um fluxo manualmente, devemos invocar o seu método flush – O método flush é válida em qualquer fluxo de saída, mas não

tem efeito a menos que o fluxo possua um buffer

Page 25: Aula Persistência 01 (Java)

E/S a partir da linha de comando

• Um programa é muitas vezes executado a partir da linha de comando e interage com o usuário no ambiente de linha de comando

• A plataforma Java dá suporte a esse tipo de interação de duas maneiras: através dos fluxos padrões e por meio do Console

Page 26: Aula Persistência 01 (Java)

Fluxos padrões

• Fluxos padrões são uma característica de muitos sistemas operacionais

• Por padrão, eles leem a entrada do teclado e escrevem a saída para o display

• Eles também dão suporte a E/S em arquivos e entre os programas, mas esse recurso é controlado pelo interpretador de linha de comando, não pelo programa

• A plataforma Java dá suporte a três fluxos padrões:

– entrada padrão, acessados através System.in

– Saída padrão, acessado através System.out

– E erro padrão, acessado através System.err

Page 27: Aula Persistência 01 (Java)

Fluxos padrões

• Esses objetos são definidos automaticamente e não precisam ser abertos

• Saída padrão e erro padrão são ambos para saída

– A saída de erro permite que o usuário separadamente desvie a saída regular para um arquivo e ainda seja capaz de ler mensagens de erro

– Para mais informações, consulte a documentação para o seu interpretador de linha de comando

Page 28: Aula Persistência 01 (Java)

Fluxos padrões

• Podemos esperar que os fluxos padrão sejam fluxos de caracteres, mas, por razões históricas, são fluxos de bytes

– System.out e System.err são definidos como objetos PrintStream

– Embora seja tecnicamente um fluxo de bytes, PrintStream usa um objeto de fluxo de caracteres interno para emular muitas das características dos fluxos de caracteres

• Em contrapartida, System.in é um fluxo de bytes sem características de transmissão de caracteres

• Para usar entrada padrão como um fluxo de caracteres, empacote System.in em InputStreamReader: InputStreamReader cin = new InputStreamReader(System.in);

Page 29: Aula Persistência 01 (Java)

O Console

• Uma alternativa mais avançada para os fluxos padrões é o Console

• Este é um objeto único, pré-definido do tipo Console

que tem a maioria dos recursos fornecidos pelos fluxos padrão, e outros além

– O Console é particularmente útil para a entrada de senha segura

• O objeto Console também fornece fluxos de entrada e saída, que são verdadeiros fluxos de caracteres, através de seus métodos de leitura e escrita

Page 30: Aula Persistência 01 (Java)

O Console

• Antes que um programa possa usar o Console, ele deve tentar recuperar o objeto Console invocando System.Console():

– Se o objeto Console está disponível, este método o retorna

– Se System.Console retorna NULL, as operações do console não são permitidas, ou porque o sistema operacional não dá suporte ou porque o programa foi lançado em um ambiente não-interativo

Page 31: Aula Persistência 01 (Java)

O Console

• O objeto Console dá suporte a entrada de senha segura através do seu método readPassword

• Este método ajuda a entrada de senha segura de duas maneiras:

– Em primeiro lugar, ele suprime o eco, para que a senha não seja visível na tela do usuário

– Em segundo lugar, readPassword retorna um array de caracteres, não uma String, para que a senha possa ser substituída, retirando-a da memória assim que ela não for mais necessária

• O exemplo Password é um programa protótipo para alterar a senha de um usuário

– Ele demonstra vários métodos do Console

Page 32: Aula Persistência 01 (Java)

import java.io.Console;

import java.util.Arrays;

import java.io.IOException;

public class Password {

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

Console c = System.console();

if (c == null) {

System.err.println("Sem console.");

System.exit(1);

}

String login = c.readLine("Entre com o login: ");

char[] senhaAntiga = c.readPassword("Entre com sua " +

"senha anterior: ");

...

}

... }

Page 33: Aula Persistência 01 (Java)

...

if (verifica(login, senhaAntiga)) {

boolean naoCombina;

do {

char[] novaSenha1 =

c.readPassword("Entre com a nova senha: ");

char[] novaSenha2 =

c.readPassword("Digite novamente: ");

naoCombina = ! Arrays.equals(novaSenha1, novaSenha2);

if (naoCombina) {

c.format("Senhas nao combinam. Tente novamente.%n");

} else {

modifica(login, novaSenha1);

c.format("Senha para %s modificada.%n", login);

}

Arrays.fill(novaSenha1, ' ');

Arrays.fill(novaSenha2, ' ');

} while (naoCombina);

}

Arrays.fill(senhaAntiga, ' ');

}

...

}

Page 34: Aula Persistência 01 (Java)

...

// Método verifica simples

static boolean verifica(String login, char[] senha) {

return true;

}

// Método modifica simples

static void modifica(String login, char[] senha) {}

}

Page 35: Aula Persistência 01 (Java)

Streams de dados

• Fluxos de dados dão suporte a E/S binária de valores de tipo de dados primitivos (boolean, char, byte, short, int, long, float e double), bem como a valores String

• Todos os fluxos de dados implementam tanto a interface DataInput como a DataOutput

– As implementações mais utilizado dessas interfaces são DataInputStream e DataOutputStream

Page 36: Aula Persistência 01 (Java)

Streams de dados

• O exemplo demonstra os fluxos de dados, escrevendo um conjunto de registros de dados e, em seguida, lendo-os novamente

• Cada registro é composto por três valores relacionados a um item em uma fatura, como mostra a tabela:

Ordem no Registro

Tipo de Dado

Descrição Método de Saída Método de entrada Valor Exemplo

1 double Preço DataOutputStream

.writeDouble

DataInputStream

.readDouble

19.99

2 int Quantidade DataOutputStream

.writeInt

DataInputStream

.readInt

12

3 String Descrição DataOutputStream

.writeUTF

DataInputStream

.readUTF

“Camiseta

Java”

Page 37: Aula Persistência 01 (Java)
Page 38: Aula Persistência 01 (Java)
Page 39: Aula Persistência 01 (Java)
Page 40: Aula Persistência 01 (Java)

Streams de dados

• Note-se que DataStream detecta uma condição de fim de arquivo pela captura de EOFException, em vez de testar por um valor de retorno inválido

• Todas as implementações de métodos de DataInput

usam EOFException em vez de valores de retorno

• Note também que cada gravação (write) especializada em DataStreams é exatamente igual ao correspondente de leitura (read) especializado

• Cabe ao programador se certificar de que os tipos de saída e tipos de entrada são combinados, desta maneira: o fluxo de entrada é composto por dados binários simples, sem nada para indicar os tipos de valores individuais ou onde começam no stream

Page 41: Aula Persistência 01 (Java)

Streams de objetos

• Assim como os fluxos de dados dão suporte a E/S de tipos de dados primitivos, fluxos de objetos dão suporte a E/S de objetos

• A maioria, mas não todas as classes padrões dão suporte a serialização de seus objetos: aquelas que implementam a interface Serializable

• As classes de fluxo de objetos são ObjectInputStream e ObjectOutputStream

• Essas classes implementam ObjectInput e ObjectOutput, que são sub-interfaces de DataInput e DataOutput

Page 42: Aula Persistência 01 (Java)

Streams de objetos

• Isso significa que todos os métodos de E/S de dados primitivos cobertos na seção Streams de Dados também são implementadas em fluxos de objetos

• Assim, um fluxo de objeto pode conter uma mistura de valores primitivos e objetos

• O exemplo ObjectStreams ilustra isto

Page 43: Aula Persistência 01 (Java)
Page 44: Aula Persistência 01 (Java)
Page 45: Aula Persistência 01 (Java)
Page 46: Aula Persistência 01 (Java)

Streams de objetos

• ObjectStreams cria o mesmo aplicativo do fluxo de dados, com um par de mudanças: – Em primeiro lugar, os preços são agora objetos BigDecimal

– Em segundo lugar, um objeto Calendar é gravado no arquivo de dados, o que indica uma data de fatura

• Se readObject() não devolver o tipo de objeto esperado, tentar convertê-lo para o tipo correto pode lançar uma ClassNotFoundException

• Neste exemplo simples, isto não pode acontecer, por isso, não tentamos capturar a exceção, em vez disso, notificamos o compilador que estamos cientes do problema, adicionando ClassNotFoundException à cláusula throws do método main

Page 47: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• Os métodos writeObject e readObject são simples de usar, mas eles contêm uma lógica de gerenciamento de objetos muito sofisticada

• Isso não é importante para uma classe como Calendar, que apenas encapsula valores primitivos, mas muitos objetos contêm referências a outros objetos

• Se readObject reconstituir um objeto a partir de um stream, ele tem que ser capaz de reconstituir todos os objetos que o objeto original referencia, esses objetos adicionais podem ter suas próprias referências, e assim por diante

Page 48: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• Nesta situação, writeObject atravessa toda a teia de referências a objetos e escreve todos os objetos na teia para o fluxo

• Assim, uma única chamada de writeObject pode fazer com que um grande número de objetos sejam enviados para o stream

Page 49: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• writeObject é invocado para escrever um único objeto chamado a

• Este objeto contém referências a objetos b e c, enquanto b contém referências a d e e

• Invocando writeObject(a) não escreve apenas a, mas todos os objetos necessários para reconstituir a, de modo que os outros quatro objetos nesta teia são escritos também

• Quando a é lido por readObject, os outros quatro objetos são lidos também, e todas as referências dos objetos originais são preservadas

Page 50: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• Podemos nos perguntar o que acontece se dois objetos no mesmo fluxo contêm referência a um único objeto

– Será que eles irão se referir a um único objeto quando são lidos de volta?

– A resposta é "sim“

• Um fluxo só pode conter uma cópia de um objeto, embora possa conter qualquer número de referências a ele

• Assim, se explicitamente escrevermos um objeto para um fluxo duas vezes, realmente estaremos escrevendo apenas a referência duas vezes

Page 51: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• Por exemplo, se o código a seguir escreve um objeto ob duas vezes em um stream: Object ob = new Object();

out.writeObject(ob);

out.writeObject(ob);

• Cada writeObject deve combinar com um readObject, assim o código de leitura do stream de volta poderia parecer com: Object ob1 = in.readObject();

Object ob2 = in.readObject();

• Isto resultaria em duas variáveis, ob1 e ob2, que fazem referência a um único objeto

Page 52: Aula Persistência 01 (Java)

Entrada e saída de objetos complexos

• No entanto, se um único objeto é gravado em dois fluxos diferentes, ele é efetivamente duplicado, se um programa ler ambos os fluxos de volta vai ver dois objetos distintos

Page 53: Aula Persistência 01 (Java)
Page 54: Aula Persistência 01 (Java)

E/S em arquivo

• Até agora nos concentramos em streams, que fornecem um modelo simples para ler e gravar dados

• Streams trabalham com uma grande variedade de fontes e destinos de dados, incluindo arquivos de disco, no entanto, streams não dão suporte a todas as operações que são comuns com os arquivos do disco

• Iremos nos concentrar em arquivos de E/S não stream

• Existem dois tópicos: – File é uma classe que nos ajuda a escrever código

independente de plataforma que analisa e manipula arquivos e diretórios

– Arquivos de acesso aleatório dão suporte ao acesso não-sequencial a dados de arquivo em disco

Page 55: Aula Persistência 01 (Java)

Objetos File

• A classe File (arquivo) torna mais fácil escrever código independente de plataforma que analisa e manipula arquivos

• O nome desta classe pode enganar: instâncias de File

representam os nomes dos arquivos, e não os arquivos – O arquivo correspondente ao nome do arquivo pode até não

existir

• Por que criar um objeto File para um arquivo que não existe? – Um programa pode usar o objeto para analisar um nome de

arquivo

– Além disso, o arquivo pode ser criado, passando o objeto File

para o construtor de algumas classes, como FileWriter

Page 56: Aula Persistência 01 (Java)

Objetos File

• Se o arquivo existir, um programa pode examinar seus atributos e realizar várias operações no arquivo, por exemplo, renomear, apagar, ou mudar suas permissões

Page 57: Aula Persistência 01 (Java)

Um arquivo possui muitos nomes

• Um objeto File contém uma string com o nome de arquivo usado para construí-lo

• Essa string nunca muda ao longo do tempo de vida do objeto

• Um programa pode usar o objeto File para obter outras versões do nome do arquivo, alguns dos quais podem ou não ser o mesmo que a string de nome de arquivo original passado para o construtor

• Suponha que um programa crie um objeto File com a chamada do construtor: File a = new File("xanadu.txt");

Page 58: Aula Persistência 01 (Java)

Um arquivo possui muitos nomes

• O programa invoca um número de métodos para obter diferentes versões do nome do arquivo

• O programa é então executado tanto em um sistema Microsoft Windows (no diretório c:\java\exemplos) como em um sistema Linux (no diretório /home/cafe/java/exemplos)

• A tabela mostra o que os métodos retornariam:

Método Chamado Retorno no Windows Retorno no Linux

a.toString() xanadu.txt xanadu.txt

a.getName() xanadu.txt xanadu.txt

a.getParent() NULL NULL

a.getAbsolutePath

()

c:\java\exemplos\xanadu.txt /home/cafe/java/exemplos/xanadu.txt

Page 59: Aula Persistência 01 (Java)

Um arquivo possui muitos nomes

• Em seguida, o mesmo programa constrói um objeto File

a partir de um nome de arquivo mais complicado, usando File.separator para especificar o nome do arquivo de uma forma independente da plataforma:

File b = new File(".." + File.separator +

"exemplos" + File.separator + "xanadu.txt");

• Embora b se refira ao mesmo arquivo que a, os métodos retornam valores ligeiramente diferentes, como mostra a Tabela

Page 60: Aula Persistência 01 (Java)

Um arquivo possui muitos nomes

• Vale a pena mencionar que File.compareTo() não considera a e b serem o mesmo, apesar deles se referirem ao mesmo arquivo, os nomes usados para construí-los são diferentes

Método Chamado Retorno no Windows Retorno no Linux

b.toString() ..\examples\xanadu.txt ../examples/xanadu.txt

b.getName() xanadu.txt xanadu.txt

b.getParent() ..\exemplos ../exemplos

b.getAbsolutePath

()

c:\java\exemplos\..\exemplo

s\xanadu.txt

/home/cafe/java/exemplos/xanadu.txt

b.getCanonicalPath

()

c:\java\exemplos\xanadu.txt /home/cafe/java/exemplos/xanadu.txt

Page 61: Aula Persistência 01 (Java)

Um arquivo possui muitos nomes

• O exemplo FileStuff cria objetos File de nomes passados na linha de comando e exerce vários métodos de informações sobre eles

• Será instrutivo executar FileStuff em uma variedade de nomes de arquivos

• Certifique-se de incluir os nomes de diretórios, bem como os nomes dos arquivos que na verdade não existem

• Tente passar para FileStuff uma variedade de nomes de caminhos relativos e absolutos

Page 62: Aula Persistência 01 (Java)
Page 63: Aula Persistência 01 (Java)
Page 64: Aula Persistência 01 (Java)
Page 65: Aula Persistência 01 (Java)
Page 66: Aula Persistência 01 (Java)

Manipulando arquivos

• Se um objeto File dê nome a um arquivo real, um programa pode usá-lo para realizar uma série de operações úteis com o arquivo – Estas incluem passar o objeto para o construtor de um stream

para abrir o arquivo para leitura ou escrita

• O método delete apaga o arquivo imediatamente, enquanto o método deleteOnExit exclui o arquivo quando a máquina virtual termina

• setLastModified define a data/hora de alteração do arquivo

• Por exemplo, para definir o tempo de modificação de xanadu.txt para o horário atual, um programa pode fazer:

new File("xanadu.txt")

.setLastModified(new Date().getTime());

Page 67: Aula Persistência 01 (Java)

Manipulando arquivos

• O método renameTo() renomeia o arquivo

– Note-se que a sequência de nome de arquivo por trás do objeto File permanece inalterada, portanto, o objeto File não vai referenciar o arquivo renomeado

Page 68: Aula Persistência 01 (Java)

Trabalhando com diretórios

• File possui alguns métodos úteis para trabalhar com diretórios

• O método mkdir cria um diretório

• O método mkdirs faz a mesma coisa, depois de criar primeiro os diretórios pais que ainda não existam

• Os métodos list e listFiles listam o conteúdo de um diretório:

– O método list retorna uma matriz de strings contendo os nomes dos arquivos

– Enquanto listFiles retorna uma matriz de objetos File

Page 69: Aula Persistência 01 (Java)

Métodos estáticos

• File contém alguns métodos estáticos úteis

• O método createTempFile cria um novo arquivo com um nome exclusivo e retorna um objeto File referindo-se a ele

• O listRoots retorna uma lista de nomes de raízes do sistema de arquivos:

– No Microsoft Windows, estes serão os diretórios raízes de unidades montadas, como a:\ e c:\

– Em sistemas UNIX e Linux, este será o diretório raiz, /

Page 70: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• Arquivos de acesso aleatório permitem o acesso não sequencial, ou aleatório, ao conteúdo de um arquivo

• Considere o formato de arquivo conhecido como ZIP

– Um arquivo ZIP contém arquivos e é tipicamente comprimido para economizar espaço

– Ele também contém uma entrada de diretório no final que indica onde os vários arquivos contidos no arquivo ZIP começam

Page 71: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• Suponha que queiramos extrair um arquivo específico a partir de um arquivo ZIP

• Se usarmos um fluxo de acesso sequencial, temos que:

1. Abrir o arquivo ZIP

2. Pesquisar o arquivo ZIP até localizar o arquivo que desejamos extrair

3. Extrair o arquivo

4. Fechar o arquivo ZIP

• Usando este procedimento, em média, temos que ler a metade do arquivo ZIP antes de encontrar o arquivo que desejamos extrair

Page 72: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• Podemos extrair o mesmo arquivo a partir do arquivo ZIP de forma mais eficiente, usando o recurso de busca de um arquivo de acesso aleatório, seguindo estes passos:

1. Abrir o arquivo ZIP

2. Procurar a entrada de diretório e localizar a entrada para o arquivo que desejamos extrair do arquivo ZIP

3. Procurar (para trás), dentro do arquivo ZIP pela posição do arquivo a extrair

4. Extrair o arquivo

5. Fechar o arquivo ZIP

• Este algoritmo é mais eficiente porque lemos somente a entrada de diretório e do arquivo que desejamos extrair

Page 73: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• A classe java.io.RandomAccessFile implementa ambas as interfaces DataInput e DataOutput e, portanto, pode ser usado tanto para leitura como escrita

• RandomAccessFile é semelhante ao FileInputStream e FileOutputStream em que você especifica um arquivo no sistema de arquivos nativo para abrir ao criá-lo

• Quando criamos um RandomAccessFile, devemos indicar se vai ser apenas para leitura ou também para gravá-lo (Devemos ser capazes de ler um arquivo, a fim de escrever nele)

Page 74: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• O código a seguir cria um RandomAccessFile para ler o arquivo chamado xanadu.txt: new RandomAccessFile("xanadu.txt", "r");

• E o código a seguir abre o mesmo arquivo tanto para leitura quanto para escrita: new RandomAccessFile("xanadu.txt", "rw");

• Depois que o arquivo foi aberto, podemos usar os métodos comuns read e write definidos nas interfaces DataInput e DataOutput para executar E/S no arquivo

Page 75: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• RandomAccessFile dá suporte à noção de um ponteiro de arquivo

• O ponteiro do arquivo indica o local atual no arquivo

• Quando o arquivo é criado pela primeira vez, o ponteiro do arquivo é definido como 0, indicando o início do arquivo

• Chamadas de métodos de leitura e escrita ajustam o ponteiro do arquivo pelo número de bytes lidos ou gravados

Page 76: Aula Persistência 01 (Java)

Arquivos de acesso aleatório

• Além dos métodos normais de E/S em arquivos, que implicitamente movem o ponteiro do arquivo quando ocorre a operação, RandomAccessFile contém três métodos para manipular explicitamente o ponteiro do arquivo:

– int skipBytes(int) move o ponteiro do arquivo para a frente um número especificado de bytes

– void seek(long) posiciona o ponteiro do arquivo antes do byte especificado

– long getFilePointer() retorna o byte atual de localização do ponteiro de arquivo

Page 77: Aula Persistência 01 (Java)

Referências

The Java Tutorial Fourth Edition: A Short Course on the Basics

Sharon Zakhour, Scott Hommel, Jacob Royal, Isaac Rabinovitch, Tom Risser, Mark Hoeber

...............................................

Publisher: Addison Wesley Professional

Pub Date: September 29, 2006

Page 78: Aula Persistência 01 (Java)

UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO

ALGORITMOS E PROGRAMAÇÃO II – 2014.2

Fábio M. Pereira

([email protected])