UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO 
ALGORITMOS E PROGRAMAÇÃO II – 2014.2 
Fábio M. Pereira 
(fabio.mpereira@uesb.edu.br)
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
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
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:
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
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.
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
Utilizando byte streams 
•Programa CopyBytes, que utiliza byte streams para copiar xanadu.txt:
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(); 
} 
} 
} 
}
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:
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
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
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
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
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:
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(); 
} 
} 
} 
}
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
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
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
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(); } } } }
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
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"));
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
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
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
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
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);
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
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
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
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: "); 
... 
} 
... 
}
... 
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, ' '); 
} 
... 
}
... 
// Método verifica simples 
static boolean verifica(String login, char[] senha) { 
return true; 
} 
// Método modifica simples 
static void modifica(String login, char[] senha) {} 
}
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
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”
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
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
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
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
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
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
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
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
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
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
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
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
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
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");
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:javaexemplos) 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:javaexemplosxanadu.txt 
/home/cafe/java/exemplos/xanadu.txt
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
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() 
..examplesxanadu.txt 
../examples/xanadu.txt 
b.getName() 
xanadu.txt 
xanadu.txt 
b.getParent() 
..exemplos 
../exemplos 
b.getAbsolutePath () 
c:javaexemplos..exemplosxanadu.txt 
/home/cafe/java/exemplos/xanadu.txt 
b.getCanonicalPath() 
c:javaexemplosxanadu.txt 
/home/cafe/java/exemplos/xanadu.txt
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
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());
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
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
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, /
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
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
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
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)
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
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
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
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
UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO 
ALGORITMOS E PROGRAMAÇÃO II – 2014.2 
Fábio M. Pereira 
(fabio.mpereira@uesb.edu.br)

Aula Persistência 01 (Java)

  • 1.
    UNIVERSIDADE ESTADUAL DOSUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO ALGORITMOS E PROGRAMAÇÃO II – 2014.2 Fábio M. Pereira (fabio.mpereira@uesb.edu.br)
  • 2.
    Roteiro •Fluxo deE/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
  • 4.
    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
  • 5.
    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:
  • 6.
    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
  • 7.
    Byte streams •Vamosusar 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.
  • 8.
    Byte streams •Programasusam 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
  • 9.
    Utilizando byte streams •Programa CopyBytes, que utiliza byte streams para copiar xanadu.txt:
  • 10.
    import java.io.FileInputStream; importjava.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(); } } } }
  • 11.
    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:
  • 12.
    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
  • 13.
    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
  • 14.
    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
  • 15.
    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
  • 16.
    Usando streams decaracteres •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:
  • 17.
    import java.io.FileReader; importjava.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(); } } } }
  • 18.
    Usando streams decaracteres •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
  • 19.
    E/S orientada alinha •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
  • 20.
    E/S orientada alinha •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
  • 21.
    import java.io.FileReader; importjava.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(); } } } }
  • 22.
    Buffered streams •Amaioria 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
  • 23.
    Buffered streams •Umprograma 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"));
  • 24.
    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
  • 25.
    E/S a partirda 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
  • 26.
    Fluxos padrões •Fluxospadrõ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
  • 27.
    Fluxos padrões •Essesobjetos 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
  • 28.
    Fluxos padrões •Podemosesperar 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);
  • 29.
    O Console •Umaalternativa 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
  • 30.
    O Console •Antesque 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
  • 31.
    O Console •Oobjeto 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
  • 32.
    import java.io.Console; importjava.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: "); ... } ... }
  • 33.
    ... 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, ' '); } ... }
  • 34.
    ... // Métodoverifica simples static boolean verifica(String login, char[] senha) { return true; } // Método modifica simples static void modifica(String login, char[] senha) {} }
  • 35.
    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
  • 36.
    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”
  • 40.
    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
  • 41.
    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
  • 42.
    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
  • 46.
    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
  • 47.
    Entrada e saídade 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
  • 48.
    Entrada e saídade 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
  • 49.
    Entrada e saídade 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
  • 50.
    Entrada e saídade 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
  • 51.
    Entrada e saídade 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
  • 52.
    Entrada e saídade 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
  • 54.
    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
  • 55.
    Objetos File •Aclasse 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
  • 56.
    Objetos File •Seo 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
  • 57.
    Um arquivo possuimuitos 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");
  • 58.
    Um arquivo possuimuitos 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:javaexemplos) 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:javaexemplosxanadu.txt /home/cafe/java/exemplos/xanadu.txt
  • 59.
    Um arquivo possuimuitos 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
  • 60.
    Um arquivo possuimuitos 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() ..examplesxanadu.txt ../examples/xanadu.txt b.getName() xanadu.txt xanadu.txt b.getParent() ..exemplos ../exemplos b.getAbsolutePath () c:javaexemplos..exemplosxanadu.txt /home/cafe/java/exemplos/xanadu.txt b.getCanonicalPath() c:javaexemplosxanadu.txt /home/cafe/java/exemplos/xanadu.txt
  • 61.
    Um arquivo possuimuitos 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
  • 66.
    Manipulando arquivos •Seum 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());
  • 67.
    Manipulando arquivos •Omé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
  • 68.
    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
  • 69.
    Métodos estáticos •Fileconté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, /
  • 70.
    Arquivos de acessoaleató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
  • 71.
    Arquivos de acessoaleató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
  • 72.
    Arquivos de acessoaleató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
  • 73.
    Arquivos de acessoaleató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)
  • 74.
    Arquivos de acessoaleató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
  • 75.
    Arquivos de acessoaleató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
  • 76.
    Arquivos de acessoaleató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
  • 77.
    Referências The JavaTutorial 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
  • 78.
    UNIVERSIDADE ESTADUAL DOSUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO ALGORITMOS E PROGRAMAÇÃO II – 2014.2 Fábio M. Pereira (fabio.mpereira@uesb.edu.br)