Programação por Objectos Java

Propaganda
Programação por Objectos
Java
Parte 11: Entradas / Saídas
LEEC@IST
Java – 1/72
Introdução
• É comum separar os dados que entram ou saem do
ambiente para o programa em informação binária e
informação textual.
• Informação binária: constituída por zeros e uns que
codificam qualquer tipo de dados e que têm que ser
intepretados pela aplicação.
• Informação textual: constituída por letras, dígitos,
caracteres especiais que no Java corresponde ao
tipo primitivo char (UTF-16).
LEEC@IST
Java – 2/72
Pacote java.io
• Todas as classes de manipulação de ficheiros estão
contidas no pacote java.io.
• Classes que acedem a ficheiros devem ter a
directiva:
import java.io.*;
LEEC@IST
Java – 3/72
Pacote java.io
• O pacote java.io é dividido em 5 partes:
1. Fluxo binário (byte stream):
–
–
fluxo de entrada (input stream).
fluxo de saída (output stream).
2. Fluxo de caracteres (character stream):
–
–
leitores (readers).
escritores (writers).
3. Fluxo de dados, que manipulam tipos primitivos de dados
(int,…) e cadeias de caracteres (String).
4. Fluxo de objectos, que transcrevem objectos para Bytes
e vice-versa.
5. Classe File, de manipulação dos atributos de ficheiros.
LEEC@IST
Java – 4/72
Fluxos pré-definidos
• No J2SE existe a classe estática final System,
derivada de Object. A classe System possui três
atributos estáticos:
– InputStream in: fluxo de entrada do programa
(normalmente teclado)
– PrintStream out: fluxo de saída do programa
(normalmente monitor)
– PrintStream err: fluxo de envio das mensagens de erro
(normalmente coincide com System.out)
LEEC@IST
Java – 5/72
Fluxos binários
• InputStream: classe abstracta que lê fluxos
binários de informação.
• OutputStream: classe abstracta que escreve fluxos
binários de informação.
• PrintStream: subclasse concreta de
OutputStream que escreve fluxos não
necessariamente binários de informação.
LEEC@IST
Java – 6/72
Classe InputStream (1)
• Alguns métodos da classe InputStream:
void close()
Encerra o fluxo binário de entrada e liberta todos os recursos
associados.
abstract int read()
Lê o byte seguinte do fluxo binário de entrada. O byte lido é
retornado como um int. Se nenhum byte é lido retorna -1.
int read(byte[] b)
Lê um determinado número de bytes do fluxo binário de entrada para
o tampão b. O número de bytes lidos é retornado.
int read(byte[] b, int off, int len)
Lê no máximo len bytes do fluxo binário de entrada para o tampão
b, colocando-os em b apartir da posição off. O número de bytes
lidos é retornado.
LEEC@IST
Java – 7/72
Classe InputStream (2)
long skip(long n)
Salta n bytes do fluxo binário de entrada. Pode acontecer que se
salte um número m<n de bytes, possivelmente m=0, por diversas
razões, EOF antes dos n bytes é uma das razões. É retornado o
número de bytes saltado. Se n é negativo, não foram saltados bytes.
boolean markSupported()
Verifica se o fluxo binário de entrada suporta marcas.
void mark(int readLimit)
Marca a posição actual no fluxo binário de entrada. O argumento
readLimit é o número máximo de bytes que podem ser lidos antes da
marca se tornar inválida.
void reset()
Regressa à marca mais recente.
LEEC@IST
Java – 8/72
Classe OutputStream
• Alguns métodos da classe OutputStream:
close()
Encerra o fluxo binário de saída e liberta todos os recursos
associados.
void flush()
Força envio de informação contida num tampão para o destino.
void write(byte[] b)
Escreve b.length bytes da tabela de bytes b para o fluxo binário
de saída.
void write(byte[] b, int off, int len)
Escreve len bytes da tabela de bytes b, começando na posição
off para o fluxo binário de saída.
LEEC@IST
Java – 9/72
Classe PrintStream
• Alguns métodos da classe PrintStream:
void print(boolean b)
void print(char c)
void print(char[] c)
void print(double d)
void print(float f)
void print(int i)
void print(long l)
void print(Object obj)
void print(String s)
Imprime o correspondente tipo.
void println()
Termina a linha corrente.
LEEC@IST
Java – 10/72
Fluxos binários para ficheiros
• File: subclasse concreta de Object que abstrai a
representação de um ficheiro e caminho de directorias.
• FileDescriptor: subclasse final de Object que
representa um ficheiro aberto.
• FileInputStream: subclasse concreta de
InputStream que lê fluxos binários de informação de
um ficheiro (File ou FileDescriptor).
• FileOutputStream: subclasse concreta de
OutputStream que escreve fluxos binários de
informação para um ficheiro (File ou
FileDescriptor).
LEEC@IST
Java – 11/72
Class File
• Alguns construtores da classe File:
File(String pathname)
Cria um ficheiro com a pathname recebida. A pathname pode
ser relativa ou absoluta. No caso de ser relativa, é resolvida tendo em
consideração a directoria corrente do utilizador.
• Alguns métodos da classe File:
boolean exists()
boolean canRead()
boolean canWrite()
boolean delete()
long length()
String getName()
String getPath()
LEEC@IST
Testa existência física do ficheiro.
Testa privilégios de leitura do ficheiro.
Testa privilégios de escrita do ficheiro.
Apaga o ficheiro.
Retorna a dimensão do ficheiro.
Retorna o nome do ficheiro.
Retorna o caminho do ficheiro.
Java – 12/72
Classe FileDescriptor
• Um objecto FileDescriptor representa um valor
dependente do sistema operativo que descreve um
ficheiro aberto.
• As aplicações não devem criar objectos do tipo
FileDescriptor, estes devem antes ser obtidos
apartir do método getFD dos FileInputStream e
FileOutputStream.
LEEC@IST
Java – 13/72
Classe FileInputStream
• Construtores da classe FileInputStream:
FileInputStream(File file)
FileInputStream(FileDescriptor fdObj)
FileInputStream(String name)
Cria um FileInputStream a partir do ficheiro recebido.
• Para além dos métodos típicos de close, read,
skip, etc, tem ainda o seguinte método:
FileDescriptor getFD()
Retorna o objecto FileDescriptor que representa o ficheiro,
no sistema de ficheiros, que está a ser usado pelo
FileInputStream.
LEEC@IST
Java – 14/72
Classe FileOutputStream
• Construtores da classe FileOutputStream:
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(FileDescriptor fdObj)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
Cria um FileOutputStream a partir do ficheiro recebido. Os
construtores que recebem um boolean append escrevem no fim do
ficheiro se append for true e escrevem no início do ficheiro se append
for false.
• Para além dos métodos típicos de close, write,
etc, tem ainda o seguinte método:
FileDescriptor getFD()
Retorna o objecto FileDescriptor que representa o ficheiro, no
sistema de ficheiros, que está a ser usado pelo FileOutputStream.
LEEC@IST
Java – 15/72
Exemplos de fluxos binários
import java.io.*;
// ...
int nbytes=0;
FileInputStream f = new FileInputStream(“teste”);
while(f.read() != -1)
nBytes++;
System.out.println(“Número = “ + nBytes);
f.close()
// ...
import java.io.*;
// ...
FileOutputStream f = new FileOutputStream(“teste”);
f.write(65); f.write(66); f.write(67);
f.close()
// ...
LEEC@IST
Java – 16/72
Fluxos de caracteres
• Reader: a classe abstracta que lê fluxos de caracteres.
• Writer: a classe abstracta que escreve fluxos de caracteres.
• InputStreamReader: a subclasse concreta de Reader que lê
fluxos binários de informação e que os descodifica em
caracteres usando um determinado charset.
• OutputStreamWriter: a subclasse concreta de Writer que
codifica caracteres em bytes, usando um determinado charset,
e os escreve em fluxos binários de informação.
LEEC@IST
Java – 17/72
Charsets padrão
• Qualquer implementação da plataforma Java suporta
os seguintes charsets:
–
–
–
–
–
–
US-ASCII
Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
Unicode character set.
ISO-8859-1
ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
UTF-8
Eight-bit UCS Transformation Format.
UTF-16BE
Sixteen-bit UCS Transformation Format, big-endian byte order.
UTF-16LE
Sixteen-bit UCS Transformation Format, little-endian byte order.
UTF-16
Sixteen-bit UCS Transformation Format, byte order identified by an
optional byte-order mark.
LEEC@IST
Java – 18/72
Classe InputStreamReader (1)
• Alguns construtores da classe InputStreamReader:
InputStreamReader(InputStream in)
Cria um InputStreamReader com um charset default da
correspondente JVM (normalmente o charset do sistema operativo).
InputStreamReader(InputStream in, String charsetName)
Cria um InputStreamReader com o charset recebido como
parâmetro.
• A classe InputStreamReader é um embrulho dum
objecto InputStream.
LEEC@IST
Java – 19/72
Classe InputStreamReader (2)
• Alguns métodos da classe InputStreamReader:
void close()
Encerra o fluxo de entrada e liberta todos os recursos associados.
String getEncoding()
Retorna o nome do charset usado pelo fluxo de entrada.
int read()
Lê um caracter do fluxo de entrada. O caracter lido é retornado como um int. Se
nenhum caracter é lido retorna -1.
int read(char[] cbuf, int off, int len)
Lê no máximo len caracter do fluxo de entrada para o tampão cbuf, colocandoos em cbuf apartir da posição off. O número de caracteres lidos é retornado. Se
nenhum caracter é lido retorna -1.
LEEC@IST
Java – 20/72
Classe OutputStreamWriter (1)
• Alguns construtores da classe OutputStreamWriter:
OutputStreamWriter(OutputStream in)
Cria um OutputStreamWriter com um charset default da correspondente
JVM (normalmente o charset do sistema operativo)
OutputStreamWriter(OutputStream in, String charsetName)
Cria um OutputStreamWriter com o charset recebido como parâmetro.
• A classe OutputStreamWriter é um embrulho dum
objecto OutputStream.
LEEC@IST
Java – 21/72
Classe OutputStreamWriter (2)
• Alguns métodos da classe OutputStreamWriter:
void close()
Encerra o fluxo de entrada e liberta todos os recursos associados.
void flush()
Força envio de informação contida num tampão para o destino.
String getEncoding()
Retorna o nome do charset usado pelo fluxo de entrada.
void write(char[] cbuf, int off, int len)
Escreve len caracteres da tabela cbuf, começando na posição off para o fluxo
de saída.
void write(String str, int off, int len)
Escreve len caracteres da String str, começando na posição off para o
fluxo de saída.
LEEC@IST
Java – 22/72
Fluxos de carateres para
ficheiros
• FileReader: a subclasse concreta de
InputStreamReader para ler ficheiros de
caracteres.
• FileWriter: a subclasse concreta de
OutputStreamWriter para escrever para
ficheiros de caracteres.
LEEC@IST
Java – 23/72
Classe FileReader
• Construtores da classe FileReader:
FileReader(File file)
FileReader(FileDescriptor fdObj)
FileReader(String name)
Cria um FileReader a partir do ficheiro recebido.
LEEC@IST
Java – 24/72
Classe FileWriter
• Construtores da classe FileWriter:
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(FileDescriptor fdObj)
FileWriter(String name)
FileWriter(String name, boolean append)
Cria um FileWriter a partir do ficheiro recebido. Os construtores
que recebem um boolean append escrevem no fim do ficheiro se
append for true e escrevem no início do ficheiro se append for false.
LEEC@IST
Java – 25/72
Exemplos de fluxos de
caracteres (1)
import java.io.*;
// ...
int c, uns=0;
FileReader f = new FileReader(“teste”);
while(c = f.read() != -1)
if ((char)c == ‘1’)
uns++;
System.out.println(“Ocorreram = “ + uns + “uns!”);
f.close()
// ...
LEEC@IST
Java – 26/72
Exemplos de fluxos de
caracteres (2)
class LeituraDeInteiro {
public static void main(String[] args) throws IOException {
int ch, value=0;
Reader in = args.length==0 ?
new InputStreamReader(System.in) :
new FileReader(args[0]);
for( ;(ch=in.read()!=-1; )
value=10*value+ch-(int)'0';
System.out.println("Inteiro lido = " + value);
}
}
LEEC@IST
Java – 27/72
Transferência por tampão (1)
• Tipicamente, os fluxos de entrada e saída
transferem de imediato cada dado.
• Para tornar as operações de leitura/escrita mais
eficientes, deve usar-se um tampão (buffer).
LEEC@IST
Java – 28/72
Transferência por tampão (2)
<<abstract>>
InputStream
<<abstract>>
OutputStream
FilterInputStream
FilterOutputStream
Transferência por tampão
DataInputStream
BufferedInputStream
DataOutputStream BufferedOutputStream PrintStream
Transferência imediata
LEEC@IST
Java – 29/72
Transferência por tampão (3)
• FilterInputStream: a subclasse concreta de
InputStream que embrulha outro fluxo de entrada
que usa para transferência de dados.
• FilterOutputStream: a subclasse concreta de
OutputStream que embrulha outro fluxo de saída
que usa para transferência de dados.
• FilterReader: a subclasse abstracta de Reader
que embrulha outro fluxo de entrada que usa para
transferência de dados.
• FilterWriter: a subclasse abstracta de Writer
que embrulha outro fluxo de saída que usa para
transferência de dados.
LEEC@IST
Java – 30/72
Transferência por tampão (4)
• Tipicamente, subclasses de FilterInputStream,
FilterOutputStream, FilterReader e
FilterWriter, redefinem algum dos seus
métodos e/ou adicionam membros com novas
funcionalidades.
LEEC@IST
Java – 31/72
Transferência por tampão (5)
public class ConversorParaMaiusculas extends FilterReader {
public ConversorParaMaiusculas(Reader in) {
super(in);
}
public in read()
throws IOException {
int c = super.read();
return (c==-1 ? c : Character.toUpperCase((char)c);
}
public int read(char[] buf, int offset, int count)
throws IOException {
int n = super.read(buf,offset,count);
int ultimo = offset+n;
for (int i=offset;i<ultimo;i++)
buf[i] = Character.toUpperCase(buf[i]);
return n;
}
}
LEEC@IST
Java – 32/72
Transferência por tampão (6)
public static void main(String[] args) throws IOException {
FileReader src = new FileReader(args[0]);
FilterReader fr = new ConversorParaMaiusculas(src);
int c;
while ((c=f.read())!=-1)
System.out.print((char)c);
System.out.println();
}
LEEC@IST
Java – 33/72
Transferência por tampão (7)
• Fluxos com transferência por tampão:
–
–
–
–
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
LEEC@IST
Java – 34/72
Transferência por tampão (8)
• BufferedInputStream: a subclasse concreta de
FilterInputStream com transferência por tampão
e métodos mark e reset.
• BufferedOutputStream: a subclasse concreta de
FilterOutputStream com transferência por
tampão.
• BufferedReader: a subclasse concreta de Reader
com transferência por tampão e métodos mark e
reset.
• BufferedWriter: a subclasse concreta de Writer
com transferência por tampão.
LEEC@IST
Java – 35/72
Transferência por tampão (9)
• Construtores da classe BufferedInputStream:
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
Cria um BufferedInputStream que embrulha o fluxo de
entrada recebido. O size recebido no segundo construtor é relativo
ao tamanho do tampão.
LEEC@IST
Java – 36/72
Transferência por tampão (10)
•
•
•
Quando um read é inicialmente chamado num
BufferedInputStream, este chama um read no
correspondente fluxo de entrada, enchendo o tampão (se
existirem dados suficientes).
Novas chamadas a read retornam dados do tampão.
Quando todo o tampão foi lido, é chamado de novo o read
sobre o correspondente fluxo de entrada.
Este processo continua até que o correspondente fluxo de
entrada é completamente lido.
File
BufferedInputStream
FileInputStream
LEEC@IST
tampão
Programa Java
{
…
…
}
Java – 37/72
Transferência por tampão (11)
• Construtores da classe BufferedOutputStream:
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
Cria um BufferedOutputStream que embrulha o fluxo de
saída recebido. O size recebido no segundo construtor é relativo
ao tamanho do tampão.
LEEC@IST
Java – 38/72
Transferência por tampão (12)
• De forma semelhante ao read:
– Só quando um write, chamado num
BufferedOutputStream, enche o tampão, é que é
chamado um write no correspondente fluxo de saída
para esvaziar o tampão.
– Este tampão pode fazer com que vários pequenos
pedidos de write num BufferedInputStream sejam
transformados apenas num write no correspondente
fluxo de saída.
LEEC@IST
Java – 39/72
Transferência por tampão (13)
• A escrita é feita via tabelas de bytes:
void write(byte[] b,int off,int len)
void write(byte b)
• Antes de fechar um ficheiro de escrita com tampão, é
necessário chamar o método flush, para todos os
bytes armazenados serem enviados para o meio:
void flush()
• O fecho de ficheiros é executado na chamada do
método definido na classe FilterOutputStream:
void close()
LEEC@IST
Java – 40/72
Transferência por tampão (14)
• Construtores da classe BufferedReader:
BufferedReader(Reader in)
BufferedInputStream(Reader in, int size)
Cria um BufferedReader que embrulha o fluxo de entrada
recebido. O size recebido no segundo construtor é relativo ao tamanho
do tampão.
• Construtores da classe BufferedWriter:
BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)
Cria um BufferedWriter que embrulha o fluxo de saída
recebido. O size recebido no segundo construtor é relativo ao tamanho
do tampão.
LEEC@IST
Java – 41/72
Transferência por tampão (15)
• Alguns métodos da classe BufferedWriter:
void newLine()
Escreve um separador de linha. Depende do sistema (não
necessariamente o ‘\n’).
LEEC@IST
Java – 42/72
Exemplos de criação de fluxos
com transferência por tampão
new BufferedInputStream(new FileInputStream(“foo.in”));
new BufferedReader(new FileReader(“foo.in”));
new BufferedOutputStream(new FileOutputStream(“foo.out”));
new BufferedWriter(new FileWriter(“foo.out”));
LEEC@IST
Java – 43/72
Fluxos de dados (1)
• DataInput: interface que define métodos de leitura
para os tipos primivitos e cadeias de caracteres.
• DataOutput: interface que define métodos de escrita
para os tipos primitivos e cadeias de caracteres.
• DataInputStream: implementação da interface
DataInput.
• DataOutputStream: implementação da interface
DataOutput.
• RandomAccessFile: classe concreta que implementa
as interfaces DataInput e DataOutput para acesso
aleatório a um ficheiro.
LEEC@IST
Java – 44/72
Fluxos de dados (2)
• Métodos de leitura/escrita:
Tipo
Escrita
boolean
void writeBoolean(boolean)
boolean readBoolean()
char
void writeChar(char)
char readChar()
byte
void writeByte(byte)
byte readByte()
short
void writeShort(short)
short readShort()
int
void writeInt(int)
int readInt()
long
void writeLong(long)
long readLong()
float
void writeFloat(float)
float readFloat()
double
void writeDouble(double)
double readDouble()
String
void writeUTF(String)
String readUTF()
LEEC@IST
Leitura
Java – 45/72
Fluxos de dados (3)
• Os ficheiros binários:
– São fluxos de bytes.
– Têm de ser abertos explicitamente pelo
programador antes de serem acedidos.
• Abertura de ficheiros:
– Erro na abertura gera excepção FileNotFoundException.
DataOutputStream idOut =
new DataOutputStream(new FileOutputStream(“foo.out”));
DataInputStream idIn =
new DataInputStream(new FileInputStream(“foo.in”));
LEEC@IST
Java – 46/72
Exemplos de fluxos de dados (1)
import java.io.*;
public class Teste {
public static void main(String[] args){
DataOutputStream idOut;
try {
idOut = new DataOutputStream(
new FileOutputStream(args[0]));
for(int k=0;k<10;k++)
idOut.writeUTF("Linha " + k + "\n");
idOut.close();
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
LEEC@IST
Java – 47/72
Exemplos de fluxos de dados (2)
import java.io.*;
public class Teste {
public static void main(String[] args){
DataOutputStream idOut;
try {
idOut = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(args[0])));
for(char c='a';c<='z';c++) {
idOut.write((byte)c);
idOut.write((byte)'\n');
}
idOut.flush();
idOut.close();
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
LEEC@IST
Java – 48/72
Exemplos de fluxos de dados (3)
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
try {
String input = stdin.readLine();
System.out.println("Linha comando: " + input);
} catch(IOException e) {
System.err.println(“Erro na leitura do comando“);
}
LEEC@IST
Java – 49/72
Acesso sequencial e aleatório
• Existem duas formas padrão de acesso a um dado
ficheiro, acesso sequencial e aleatório.
• Acesso sequencial limitado por uma ordem
sequencial de acesso – informação seguinte sempre
colocada à frente da informação anterior.
• Acesso aleatório permite avançar e recuar de forma
arbitrária.
LEEC@IST
Java – 50/72
Classe RandomAccessFile (1)
• O acesso aletaório a ficheiros é implementado pela
classe RandomAccessFile, classe concreta que
deriva de Object e que implementa as interfaces
DataInput e DataOutput.
• Construtores da classe RandonAccessFile:
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
Cria um ficheiro para ler/escrever com acesso aleatório de/para o
ficheiro recebido. O modo representa o modo de acesso do ficheiro
aberto, podendo ser: “r” (apenas leitura) ou “rw” (leitura e escrita), entre
outros.
LEEC@IST
Java – 51/72
Classe RandomAccessFile (2)
• Alguns métodos de leitura:
int read()
int read(byte[])
int read(byte[], int offset, int length)
boolean readBoolean()
byte readByte()
char readChar()
double readDouble()
float readFloat()
int readInt()
long readLong()
short readShort()
String readUTF()
LEEC@IST
Java – 52/72
Classe RandomAccessFile (3)
• Alguns métodos de escrita:
void
void
void
void
void
void
void
void
void
void
void
void
void
LEEC@IST
write(byte[])
write(byte[], int offset, int length)
writeBoolean(boolean b)
writeByte(int v)
writeBytes(String s)
writeChar(int v)
writeChars(String s)
writeDouble(double v)
writeFloat(float v)
writeInt(int v)
writeLong(long v)
writeShort(int v)
writeUTF(String str)
Java – 53/72
Classe RandomAccessFile (4)
• Alguns métodos de posicionamento:
void seek(long pos)
Posiciona-se no local indicado pelo parâmetro (se valor for
superior ao tamanho no ficheiro, posiciona-se no fim).
long length()
Retorna comprimento do ficheiro.
long setLength(long newLength)
Altera comprimento do ficheiro.
int skipBytes(int n)
Salta por cima de um número de bytes do ficheiro de entrada (valor
efectivo indicado pelo retorno).
LEEC@IST
Java – 54/72
Classe RandomAccessFile (5)
File dados = new File(“..”,”info”);
RandomAcessFile f = new RandomAcessFile(dados, “rw”);
for(int i=65;i<91;i++)
f.write(i) // escreve o alfabeto
byte[] ler = new byte[10];
f.seek(4); // salta para o quinto byte
f.read(ler,0,5); // lê as próximas 5 posições
for(int=0;i<5;i++)
System.out.println((char)ler[i] + “:”);
f.seek(3); // salta para o quarto byte
System.out.println((char)f.read());
No terminal é imprimido
LEEC@IST
E:F:G:H:I:D
Java – 55/72
InputStream Hierarchy
<<abstract>>
InputStream
ObjectInputStream
FilterInputStream
DataInputStream
LEEC@IST
FileInputStream
BufferedInputStream
Java – 56/72
Reader Hierarchy
LEEC@IST
Java – 57/72
RandomAcessFile Hierarchy
LEEC@IST
Java – 58/72
Fluxos de objectos
• ObjectInputStream: a subclasse concreta de
InputStream para leitura de objectos serializados.
• ObjectOutputStream: a subclasse concreta de
OutputStream para serialização de objectos.
• Serializable: a interface que tem de ser
implementada pelas classes que pretendem oferecer
serialização.
•
As classes ObjectInputStream e ObjectOutputStream,
quando usados conjuntamente com as classes
FileInputStream e FileOutputStream, respectivamente,
permitem guardar de forma persistente os objectos duma
aplicação.
LEEC@IST
Java – 59/72
Classe ObjectInputStream (1)
• Alguns construtores da classe ObjectInputStream:
ObjectInputStream(InputStream in)
Cria um ObjectInputStream que embrulha o fluxo de entrada
recebido.
• Alguns métodos da classe ObjectInputStream:
boolean defaultReadObject()
Lê do fluxo de entrada os valores dos atributos não estáticos e não
transientes do objecto (atributos da classe e todas as superclasses).
Object readObject()
Lê do fluxo de entrada o objecto.
• Classes que pretendam serialização atípica devem
implementar o método:
– private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException;
LEEC@IST
Java – 60/72
Classe ObjectInputStream (2)
• Outros métodos de leitura:
int read()
int read(byte[], int offset, int length)
boolean readBoolean()
byte readByte()
char readChar()
double readDouble()
float readFloat()
int readInt()
long readLong()
short readShort()
String readUTF()
LEEC@IST
Java – 61/72
Classe ObjectOutputStream (1)
• Alguns construtores da classe ObjectOutputStream:
ObjectOutputStream(OutputStream out)
Cria um ObjectOutputStream que embrulha o fluxo de saída
recebido.
• Alguns métodos da classe ObjectInputStream:
protected boolean defaultWriteObject()
Escreve no fluxo de saída os atributos não estáticos e não
transientes do objecto (atributos da classe e todas as superclasses).
void writeObject(Object obj)
Escreve no fluxo de saída o objecto obj.
• Classes que pretendam serialização atípica devem
implementar o método:
– private void writeObject(ObjectOutputStream stream)
throws IOException, ClassNotFoundException;
LEEC@IST
Java – 62/72
Classe ObjectInputStream (2)
• Outros métodos de escrita:
void
void
void
void
void
void
void
void
void
void
void
void
void
LEEC@IST
write(byte[])
write(byte[], int offset, int length)
writeBoolean(boolean b)
writeByte(int v)
writeBytes(String s)
writeChar(int v)
writeChars(String s)
writeDouble(double v)
writeFloat(float v)
writeInt(int v)
writeLong(long v)
writeShort(int v)
writeUTF(String str)
Java – 63/72
Exemplos de fluxos de objectos (1)
FileOutputStream fos = new FileOutputStream(“foo.out”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject(“Hoje”);
oos.writeObject(new Date());
oos.close();
fos.close();
FileInputStream fis = new FileInputStream(“foo.out”);
ObjectInputStream ois = new ObjectInputStream(fis);
int i = ois.readInt();
String hoje = (String) ois.readObject();
Date data = (Data) ois.readObject();
ois.close();
fis.close();
LEEC@IST
Java – 64/72
Exemplos de fluxos de objectos (2)
• Serialização de um objecto HashMap num ficheiro
para uso futuro:
FileOutputStream fos = new FileOutputStream(“hm.out”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
HashMap<?,?> hm = getHashMap();
oos.writeObject(hm);
• Uma nova cópia do objecto pode ser reconstruída a
partir da serialização anterior:
FileInputStream fis = new FileInputStream(“hm.out”);
ObjectInputStream ois = new ObjectInputStream(fis);
HashMap<?,?> hm = (HashMap<?,?>) ois.readObject();
LEEC@IST
Java – 65/72
Partilha de referências na
serialização de objectos (1)
• A serialização preserva a integridade do grafo dos
objectos em memória:
chave: “rosa”
entrada:
hm
rose.jpg
chave: “rose”
entrada:
• Quando o HashMap é reconstruído a partir da
serialização, existirão apenas referências para um
objecto rose.jpp, e não referências para duas cópias
separadas de rose.jpg.
LEEC@IST
Java – 66/72
Partilha de referências na
serialização de objectos (2)
• Quando tal não é pretendido podem usar-se os
seguintes métodos:
void writeUnshared(Object obj)
Escreve o objecto obj para o fluxo de saída, sem partilha de
referências. Isto é, escreve o objecto como um objecto distinto, em vez
de usar uma referência para a correspondente serialização desse
objecto. Qualquer objecto serializado com este método terá uma única
referência para ele quando for reconstruído em memória.
Object readUnshared()
Lê um objecto sem partilha de referência do fluxo de entrada. O
objecto é suposto ser único, se o objecto é uma referência para um
objecto já reconstruído uma excepção ObjectStreamException é
lançada. Da mesma forma, se mais tarde se tentar reconstruir um
objecto para a mesma referência uma excepção
ObjectStreamException é lançada.
LEEC@IST
Java – 67/72
Interface Serializable (1)
• Os objectos de uma aplicação podem ser escritos
num fluxo apenas se a sua classe concretizar a
interface Serializable.
• Todos os atributos de um objecto que se pretendem
serializar devem ser instância de uma classe que
concretiza Serializable.
• Se se pretender que o valor de um atributo não seja
serializado, usar na sua definição o qualificador
transient (na realidade, é enviado o literal null).
• A interface Serializable não tem atributos nem
métodos.
LEEC@IST
Java – 68/72
Interface Serializable (2)
public class Nome implements java.io.Serializable {
private String nome;
private long id;
private transient boolean hashSet = false;
private transient int hash;
private static long proxID = 0;
public Nome(String nome) {
this.nome = nome;
id = proxId++;
}
public int hashCode() {
if (!hashSet) {
hash = nome.hashCode();
hashSet = true;
}
return hash;
}
//redefinição de equals e outros métodos…
}
LEEC@IST
Java – 69/72
Interface Serializable (3)
public class Nome implements java.io.Serializable {
private String nome;
private long id;
private transient int hash;
private static long proxID = 0;
public Nome(String nome) {
this.nome = nome;
id = nextId++;
hash = nome.hashCode();
}
private void writeObject(ObjectOutputStream out)
throws IOException {
out.writeUTF(nome);
out.writeLong(id);
}
// ... continua no próximo slide
LEEC@IST
Java – 70/72
Interface Serializable (4)
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoubdException {
nome = in.readUTF();
id = in.readLong();
hash = name.hashCode();
}
public int hashCode() {
return hash;
}
//redefinição de equals e outros métodos…
}
LEEC@IST
Java – 71/72
Interface Serializable (5)
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoubdException {
in.defaultReadObject();
hash = nome.hashCode();
}
LEEC@IST
Java – 72/72
Download