Вы находитесь на странице: 1из 26

I/O em Java

(nota: os diapositivos desta aula são directamente baseados no cap. 12 de TiJ3


números de página referem-se ao PDF disponível na página da disciplina)

Miguel Pessoa Monteiro, Ph.D.


ESTCB – IPCB
O sistema do Java para I/O
•Java fornece uma biblioteca grande com classes para a
maior parte do trabalho necessário para entradas e saídas
(Input/Output ou I/O) de todos os tipos
–Comunicação por meio de ficheiros, redes, a consola
–Sequencial, acesso aleatório (random-access), buffered,
binário, por caracteres (i.e., texto), por linhas (de texto), por
palavras (texto), etc.

•Na verdade, a tarefa de aprender todas estas classes pode


ser intimidadora no início…
Caracteres Java são Unicode
•É importante ter presente que todos os caracteres do Java
são Unicode

•Isto significa que I/O baseado en texto (i.e., em caracteres) é


feito através da transmissão de caracteres de 2 bytes

•Isto pode em alguns caso ter impacto na maneira como se


programa, quando os ficheiros também são processados por
programas não-Java
A classe File
• Antes de começarmos a ver as classes que lêm e escrevem
em ficheiros, vejamos uma classe utilitária que nos permite
lidar com ficheiros

• A classe File
– Apesar do nome, não representa um ficheiro
– Representa ou o nome dum ficheiro em particular
– ou os nomes dum conjunto de ficheiros numa
directoria
– "FilePath" seria um nome mais adequado para esta
classe
A classe File
• Lembrem-se de que Java pretende ser cross-platform
(i.e., o mesmo programa *.class capaz de funcionar em
múltiplas plataformas.
• Sempre que dizemos “nome de ficheiro” temos de pensar
na questão "fully-qualified file name"
– Caminho de directorias + name
• Os separadores (path separators) dependem da
plataforma
– /etc/init.d/nfs-kernel-server (Unix)
– C:\Documents and Settings\Administrator (Windows)

• File expõe 2 campos static, separatorChar and separator


• Estes campos são inicializados com valores provenientes
das propriedades do sistema "path.separator" e
"file.separator"
A classe File
•Se um objecto File representa um conjunto de ficheiros,
podemos interrogar o objecto através do método list()
–Devolve um vector de Strings representando os ficheiros e
(sub-)directorias contidos na caminho representado pelo
objecto File
Procesamento de directorias
•Através da classe File podemos processar directorias de
muitas maneiras…
–Criar ou remover uma directoria ou caminho, ou um ficheiro
–Mudar nomes
–Verificar características dos ficheiros
•tamanho, data da última modificação, se permite leitura ou escrita

•Vejam os Javadocs de File…


Alguns métodos da Classe File
CONSTRUTORES

• File(String caminho) construtor de directórios/ficheiros

• File(String caminho,String nome) construtor com nome separado do caminho

• File(String directorio, String nome) construtor com directório e nome do ficheiro

MÉTODOS

• boolean canRead() ficheiro/directório pode ser lido

• boolean canWrite() pode-se gravar no ficheiro/directório

• boolean delete() apaga ficheiro/directório

• boolean exists() verifica se ficheiro/directório existem

• boolean isAbsolute() verifica se caminho é absoluto

• boolean isDirectory() verifica se objecto é directório

• boolean isFile() verifica se objecto é ficheiro

• boolean mKdir() cria directório do objecto

• boolean mKdirs() cria directórios do caminho

• boolean renameTo(String novo) muda nome do ficheiro/directório para novo


Filtros
•O I/O do Java basea-se no conceito de filtro
–Um filtro é uma classe que recebe algo e “filtra” tudo
excepto aquilo em que estamos interessados

•Java fornece interfaces para os diversos tipos de filtro

•Podemos escrever uma classe que implementa o filtro que


pretendemos
Listador de directorias
•O programa DirList.java no livro Thinking in Java 3rd ed
apresenta um típico exemplo do uso da classe File e de um
filtro

public class DirList {


public static void main(String[] args) {
File path = new File(".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list(new DirFilter(args[0])); //ver prox diapositivo
Arrays.sort(list, new AlphabeticComparator());
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
}
Listador de directorias
class DirFilter implements FilenameFilter {
private Pattern pattern;

public DirFilter(String regex) {


pattern = Pattern.compile(regex);
}

public boolean accept(File dir, String name) {


// Strip path information, search for regex:
return pattern.matcher(
new File(name).getName()).matches();
}
}
Listador de directorias
•A interface FilenameFilter declara um método,
boolean accept(File dir, String name)

•As classes deste tipo existem apenas para que este método
possa ser chamado
–Usualmente pelo método sobrecarregado
File.list(FilenameFilter f)

•A implementação do método na classe que implementa a


interface deve devolver um valor booleano indicando se este
objecto File passa no filtro
Listador de directorias
•Filtros representam um outro caso em que as classe
internas anónimas dão muito jeitinho

•Vejam o exemplo de Thinking in Java DirList3.java que faz a


mesma coisa, mas com apenas uma definição de classe...
...
list = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(args[0]);

public boolean accept(File dir, String name) {


return pattern.matcher(
new File(name).getName()).matches();
}
});
Arrays.sort(list, new AlphabeticComparator());
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
I/O
•As bibliotecas do Java (e não só) para I/O baseam-se na
abstracção stream

•Um stream é qualquer fonte ou poço de dados


–Qualquer objecto capaz de produzir ou receber dados

•O stream esconde os detalhes do que acontece aos dados


dentro do dispositivo concreto
I/O
•As classes Java para I/O dividem-se em entradas (input) e
saídas (output)

•Tudo o que descende das classes InputStream ou Reader


possui um método read()

•Tudo o que descnde das classes OutputStream ou Writer


possui um método write()

•Tipicamente efectuamos o nosso I/O através de múltiplos


níveis de classes
I/O
Vejamos as subclasses de InputStream
(continuem a ver os javadocs)...

• ByteArrayInputStream lê de byte[]
• StringBufferInputStream lê de String
• FileInputStream lê dum ficheiro
• PipedInputStream lê dum pipe
–pipes são um mecanismo de comunicação entre
processos (matéria da disciplina Sistemas de
Exploração)
I/O
• Para cada InputStream, existe o OutputStream
correspondente
• Todas a programação I/O seguem os mesmos padrões
–Revisão: "design pattern" é um termo usado nas
linguagens OO para uma “maneira normalizada de fazer
as coisas"
• Neste caso, é usado o padrão decorador:
vários níveis de classes, cada classe construída a partir da
anterior (como camadas de cebolas)

• Exemplo (do exemplo nas págs. 667-9 de TiJ3):

BufferedReader in = new BufferedReader(


new FileReader("IOStreamDemo.java")
);
I/O
• Há várias classes InputStream cujo construtor recebe um
InputStream
– DataInputStream, BufferedInputStream,
LineNumberInputStream

• São os chamados decoradores


– Cada classe fornece a mesma interface
– Neste caso, métodos read() e readX()

• A maioria possui os seus correspondentes OutputStream


que são usados para saídas
– Essas classes possuem métodos write() e writeX()
I/O
• Para lidar com caracteres Unicode, existem as classes
Reader e Writer (pág. 662 de TiJ3) cujos construtores
recebem InputStreams ou OutputStreams

• Estes são mais recentes na evolução do Java

• Geralmente, usamos as classes Reader e Writer para


ficheiros de texto (i.e., baseados em caracteres)
– O compilador diz-nos quando não as podemos usar
(quando fazemos I/O de bytes, por exemplo quando
lemos dum ficheiro *.zip)
I/O
•Existe ainda um caso especial, a classe RandomAccessFile
(pág.666 de TiJ3), que nos permite tratar a fonte como um
longo stream de bytes
•Usamos seek() para mudar a posição corrente do ficheiro
Exemplo da pág.669 de TiJ3:
RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");
for(int i = 0; i < 10; i++)
rf.writeDouble(i*1.414);
rf.close();
rf = new RandomAccessFile("rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
rf = new RandomAccessFile("rtest.dat", "r");
for(int i = 0; i < 10; i++)
System.out.println("Value " + i + ": " +
rf.readDouble());
rf.close();
I/O
•Vejamos agora um exemplo dum programa que usa um
BufferedReader para ler um ficheiro linha-a-linha, e escreve
cada linha no standard output (stdout – System.out)
import java.io.*;
public class BufferedReaderExample {
public static void main(String[] args) {
try {
String currentLine; //Temp storage for each line
// Create a BufferedReader
// wrapped around a FileReader
BufferedReader br = new BufferedReader(
new FileReader(args[0]));
// Read until End Of File: indicated by null
while ((currentLine=br.readLine()) != null) {
System.out.println(currentLine);
}
br.close();
} catch (FileNotFoundException e) {
System.out.println(e);
} catch (IOException e) {
System.out.println(e);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage: java "+
"BufferedReaderExample <filename>");
System.exit(0);
} // end try-catch
} // end main
} // end class BufferedReaderExample
Lendo do standard input
•Tal como usamos o stdout via System.out (que é um objecto
do tipo PrintStream), podemos usar stdin que é um
InputStream refernciado por System.in

•Geralmente “embrulhamos” este objecto num


BufferedReader por questões de desempenho

•Exemplo na pág. 677 de TiJ3


Lendo do standard input
import java.io.*;

public class Echo {


public static void main(String[] args)
throws IOException {
BufferedReader in =
new BufferedReader(
new InputStreamReader(System.in));
String s;
while((s = in.readLine()).length() != 0)
System.out.println(s);
// An empty line terminates the program
} // end main
} // end class Echo
Redirecting System.in, , .out, .err
• Podemos redireccionar System.in, System.out, e
System.err usando os métodos (de acesso)
System.setIn(), .setOut(), e .setErr()
PrintStream out = new PrintStream(
new BufferedOutputStream(
new FileOutputStream("test.out")
)
);
System.setOut(out);
Perguntas?
Opção II – Programação Avançada

Вам также может понравиться