Você está na página 1de 12

PROGRAMAÇÃO

ORIENTADA A
OBJETOS
Comandos de
entrada e saída
Rafael Leal Martins

OBJETIVOS DE APRENDIZAGEM

> Conceituar entrada e saída de dados em programação.


> Descrever os principais comandos de entrada e saída de dados.
> Praticar o desenvolvimento de pequenos programas em Java.

Introdução
Na linguagem de programação, usamos um componente do sistema de entrada
e saída de dados, o I/O (do inglês input/output, que significa “entrada/saída”).
Tradicionalmente, um dos primeiros exemplos mostrados nas linguagens de
programação é um programa que imprime uma mensagem na tela para o usuário
(tipicamente, a mensagem em inglês Hello world, que significa “Olá, mundo”).
A Java tem um sistema de I/O muito robusto e coeso, com vários componentes
que realizam essa função em diferentes cenários.
Neste capítulo, você vai estudar os conceitos dos sistemas de I/O usados na
programação de forma geral, os principais comandos de I/O de dados na lingua-
gem Java e a aplicação desses comandos em alguns exemplos de programas.
2 Comandos de entrada e saída

Conceitos de entrada/saída em
programação
O processamento de dados consiste basicamente em três etapas: entrada,
processamento e saída. Na entrada, os dados são fornecidos do mundo
externo para o sistema. No processamento, o sistema processa os dados
quando o algoritmo/programa realiza todos os cálculos e transformações
almejados. Na saída, por fim, os dados já processados retornam (são expostos)
ao mundo externo.
Para que isso aconteça, algoritmos e linguagens de programação devem
ter instruções para fazer essa comunicação com o mundo exterior ao sistema
computacional. Elas são necessárias para que o usuário forneça dados a
serem computados, além de permitir que o programa exiba informações para
o usuário. A entrada pode ser feita por vários dispositivos, como teclado,
mouse, arquivos, scanners, câmeras, sensores, etc. A saída pode ser feita na
tela de monitores, na impressora, em arquivos, entre outros (ORACLE, c2021).
Desde quando aprendemos os princípios básicos de programação em Java,
usamos alguma parte do sistema de I/O Java, como a instrução println ().
O sistema de I/O Java é bem diverso, contendo várias classes, interfaces e
métodos. A Java define dois sistemas de I/O completos: um para I/O de bytes,
e o outro para I/O de caracteres (SCHILDT, 2015). Na próxima seção, vamos
estudar os recursos mais usados e importantes do sistema de I/O de Java.

Comandos de entrada e saída em Java


O sistema de I/O Java é coeso e coerente. Por isso, quando entendemos seus
aspectos básicos, fica fácil dominá-lo. Os programas Java executam operações
de I/O por intermédio de fluxos. Um fluxo de I/O é uma abstração que produz
ou consome informações e é vinculado a um dispositivo físico pelo sistema
de I/O Java (SCHILDT, 2015).
Todos os fluxos se comportam de forma similar, ainda que os dispositivos
físicos aos quais estejam vinculados sejam diferentes. Isso faz com que as
mesmas classes e os mesmos métodos de I/O sejam aplicados a qualquer
tipo de dispositivo. Por exemplo, os métodos usados para escrita de dados
em console também podem ser usados na escrita em um arquivo em disco.
Os fluxos de I/O são definidas no pacote java.io.
Comandos de entrada e saída 3

A Java define dois tipos de fluxos de I/O: fluxos de bytes e fluxos de carac-
teres. Os fluxos de bytes são usados, por exemplo, na leitura ou na escrita de
dados binários. São especialmente úteis para manipular arquivos. Os fluxos
de caracteres usam o Unicode e, portanto, podem ser internacionalizados.

As classes de I/O descritas aqui dão suporte a I/O de arquivo e a


I/O de console com base em textos. Elas não são usadas para criar
interfaces gráficas de usuário (GUIs).

Classes de I/O de fluxos de bytes


Os fluxos de bytes são definidos com duas hierarquias de classes. No topo
dessa hierarquia, estão as duas classes abstratas a seguir (ORACLE, c2021).

„ InputStream: define as características dos fluxos de entrada de bytes.


„ OutputStream: define as características dos fluxos de saída de bytes.

A partir dessas classes, derivam-se muitas subclasses concretas que


realizam operações de leitura e escrita em vários dispositivos, como console
ou arquivos em disco. As classes de fluxo de bytes são mostradas a seguir
(SCHILDT, 2015).

„ BufferedInputStream: fluxo de entrada armazenado em buffer.


„ BufferedOutputStream: fluxo de saída armazenado em buffer.
„ ByteArrayInputStream: fluxo de entrada que lê de um array de bytes.
„ ByteArrayOutputStream: fluxo de saída que grava em um array
de bytes.
„ DataInputStream: fluxo de entrada que contém métodos para a
leitura dos tipos de dados-padrão Java.
„ DataOutputStream: fluxo de saída que contém métodos para a gra-
vação dos tipos de dados-padrão Java.
„ FileInputStream: fluxo de entrada que lê de um arquivo.
„ FileOutputStream: fluxo de saída que grava em um arquivo.
„ FilterInputStream: implementa InputStream.
„ FilterOutputStream: implementa OutputStream.
„ InputStream: classe abstrata que descreve a entrada em fluxo.
4 Comandos de entrada e saída

„ ObjectInputStream: fluxo de entrada para objetos.


„ ObjectOutputStream: fluxo de saída para objetos.
„ OutputStream: classe abstrata que descreve a saída em fluxo.
„ PipedInputStream: pipe de entrada.
„ PipedOutputStream: pipe de saída.
„ PrintStream: fluxo de saída que contém print () e println ().
„ PushbackInputStream: fluxo de entrada que permite que bytes
retornem para o fluxo.
„ SequenceInputStream: fluxo de entrada que é uma combinação de
dois ou mais fluxos de entrada lidos sequencialmente, um após o outro.

Classes de I/O de fluxos de bytes


Os fluxos de caracteres são definidos com duas hierarquias de classes que
têm no seu topo as classes abstratas: Reader e Writer. A Reader é usada
para entrada (leitura), e a Writer, para saída (escrita). As classes derivadas
dessas duas operam com fluxos de caracteres Unicode e tratam várias situa-
ções de I/O. Em geral, as classes baseadas em caracteres são equivalentes
às baseadas em bytes. Confira a seguir (SCHILDT, 2015).

„ BufferedReader: fluxo de caractere de entrada armazenado em buffer.


„ BufferedWriter: fluxo de caractere de saída armazenado em buffer.
„ CharArrayReader: fluxo de entrada que lê de um array de caracteres.
„ CharArrayWriter: fluxo de saída que grava em um array de caracteres.
„ FileReader: fluxo de entrada que lê de um arquivo.
„ FileWriter: fluxo de saída que grava em um arquivo.
„ FilterReader: leitor filtrado.
„ FilterWriter: gravador filtrado.
„ InputStreamReader: fluxo de entrada que converte bytes em
caracteres.
„ LineNumberReader: fluxo de entrada que conta linhas.
„ OutputStreamWriter: fluxo de saída que converte caracteres em
bytes.
„ PipedReader: pipe de entrada.
„ PipedWriter: pipe de saída.
„ PrintWriter: fluxo de saída que contém print () e println ().
„ PushbackReader: fluxo de entrada que permite que caracteres sejam
retornados para o fluxo.
„ Reader: classe abstrata que descreve a entrada de caracteres em fluxo.
Comandos de entrada e saída 5

„ StringReader: fluxo de entrada que lê de uma string.


„ StringWriter: fluxo de saída que grava em uma string.
„ Writer: classe abstrata que descreve a saída de caracteres em fluxo.

Os computadores lidam basicamente apenas com números. Letras e


outros caracteres são manipulados pelos sistemas atribuindo-se um
valor numérico para cada um. O padrão Unicode foi desenvolvido para representar
os sistemas de escrita usados por todas as línguas do mundo (UNICODE, c2021).

Fluxos predefinidos em Java


Todos os programas Java importam automaticamente o pacote java.lang.
Esse pacote define uma classe chamada System, que encapsula vários as-
pectos do ambiente de tempo de execução. A classe System contém três
variáveis de fluxo predefinidas: in, out e err.

„ System.out é um objeto de tipo InputStream e representa o fluxo de


saída básico. Por padrão, ele usa o console para exibir as informações
para o usuário.
„ System.in é um objeto do tipo InputStream responsável pela entrada
de dados pelo teclado.
„ System.err é um objeto do tipo PrintStream que também usa o
console para saída de dados, mas mais especificamente para saída de
mensagens de erro da aplicação.

Todos eles são fluxos de bytes, apesar de normalmente usados na leitura


e na gravação de caracteres no console. A classe InputStream e todas as
classes derivadas dela têm um conjunto em comum de métodos para realizar
a leitura de dados de entrada, conforme seguem.

„ int available(): retorna o número de bytes de entrada atualmente


disponíveis para leitura.
„ void close(): fecha a origem da entrada. Tentativas de leitura adi-
cionais geram uma IOException.
„ void mark(int numBytes): insere uma marca no ponto atual do fluxo
de entrada que permanecerá válida até numBytes bytes serem lidos.
6 Comandos de entrada e saída

„ boolean markSupported(): retorna true se mark( )/reset()


tiverem suporte no fluxo chamador.
„ int read(): retorna uma representação em inteiros do próximo
byte disponível da entrada. É retornado –1 quando o fim do fluxo é
alcançado.
„ int read(byte buffer[]): tenta ler até buffer.length bytes
em buffer e retorna o número de bytes que foram lidos com sucesso.
É retornado –1 quando o fim do fluxo é alcançado.
„ int read(byte buffer[], int deslocamento, int num-
Bytes): tenta ler até numBytes bytes em buffer começando em
buffer[deslocamento] e retornando o número de bytes lidos com
sucesso. É retornado –1 quando o fim do fluxo é alcançado.
„ void reset(): volta o ponteiro da entrada à marca definida
anteriormente.
„ long skip(long numBytes): ignora (isto é, salta) numBytes bytes
da entrada, retornando o número de bytes ignorados.

A classe OutputStream e suas subclasses também têm um conjunto


comum de métodos para escrita de dados (saída), conforme listados a seguir
(SCHILDT, 2015).

„ void close(): fecha o fluxo de saída. Tentativas de gravação adicionais


geram uma IOException.
„ void flush(): faz qualquer saída que tiver sido armazenada em buffer
ser enviada para seu destino, isto é, esvazia o buffer de saída.
„ void write(int b): grava um único byte em um fluxo de saída.
Observe que o parâmetro é um int, o que permite chamar write()
com expressões sem ter que convertê-las novamente para byte.
„ void write(byte buffer[]): grava um array de bytes completo em
um fluxo de saída.
„ void write(byte buffer[], int deslocamento, int num-
Bytes): grava um subconjunto de numBytes bytes a partir do array
buffer, começando em buffer[deslocamento].
Comandos de entrada e saída 7

Como System.in é do tipo InputStream, temos acesso aos métodos


definidos por InputStream. Entretanto, um InputStream só define um
método de entrada: o método read(), que lê bytes do teclado. Confira a
seguir as três versões do método read() (SCHILDT, 2015):

1. int read() throws IOException.


2. int read(byte dados[]) throws IOException.
3. int read(byte dados[], int início, int max) throws
IOException.

A saída no console é obtida mais facilmente com os métodos print() e


println(). Esses métodos são definidos pela classe PrintStream (que é o
tipo do objeto referenciado por System.out). Mesmo que System.out seja
um fluxo de bytes, é aceitável usar esse fluxo para saídas simples no console.
A classe Scanner, empacotada em java.util pode ser usada para ler
dados de entrada. Um objeto Scanner pode ser usado na leitura de entradas
de várias fontes, inclusive do console e de arquivos. Portanto, você pode usá-la
para ler uma string numérica inserida pelo teclado e atribuir seu valor a uma
variável. Para usar um objeto isso, primeiro você deve criar um objeto Scanner
vinculado à entrada do console usando o construtor Scanner(InputStream
origem). Ele cria um Scanner que usa o fluxo especificado por origem como
fonte de entrada. Para criar um Scanner vinculado à entrada do console, você
pode usar o construtor Scanner entrada = new Scanner(System.in).
Após essa linha ser executada, o objeto entrada pode ser usado na
leitura de entradas do teclado. Uma vez que você tiver criado um Scanner,
é só usá-lo para ler entradas de vários tipos de dados, chamando um dos
métodos hasNextX de Scanner, onde X é o tipo de dado desejado. Todos
os métodos hasNextX retornam true quando o tipo de dado desejado é o
próximo item disponível no fluxo de dados; caso contrário, retornam false.
Se a entrada estiver disponível, é preciso lê-la chamando um dos métodos
nextX de Scanner. Para ler um valor inteiro, usamos o método nextInt().
Para ler um valor do tipo double, utilizamos nextDouble(). Já para ler uma
palavra (String) ou uma linha de texto, utilizamos next() e nextLine(),
respectivamente.
8 Comandos de entrada e saída

Usando comandos de I/O em Java


Veremos agora um exemplo de como utilizar alguns dos principais comandos
de entrada e saída (I/O) em um programa Java. A entrada de dados será feita
com objetos Scanner, e a saída, com System.out.print().
Vamos criar um programa em Java para ler o código de um produto (valor
do tipo int), seu nome (String) e seu preço unitário (double) e exibir essas
informações para o usuário.

Arquivo: Exemplo1.java
01: import java.util.Scanner;
02: public class Exemplo1 {
03:   public static void main(String[] args) {
04:     Scanner entrada = new Scanner(System.in);
05:     int codigo;
06:     String nome;
07:     double preco;
08:    
09:     System.out.print("Digite o código do produto: ");
10:     codigo = entrada.nextInt();
11:     System.out.print("Digite o nome do produto: ");
12:     nome = entrada.next();
13:     System.out.print("Digite o preço do produto: ");
14:     preco = entrada.nextDouble();
15:
16:     System.out.println("Produto cadastrado: ");
17:     System.out.println("Código: " + codigo);
18:     System.out.println("Nome: " + nome);
19:     System.out.println("Preço: " + preco);
20:
21:   }

Para usarmos a classe Scanner para ler dados do teclado, precisamos


importar essa classe do pacote java.util (linha 01). Criamos na linha 04
um objeto Scanner chamado entrada, que lê dados da entrada padrão
(System.in).
Comandos de entrada e saída 9

Usamos o comando System.out.print para escrever na saída padrão


(console) mensagens informando ao usuário quais dados devem ser digitados
(linhas 09, 11 e 13). Por utilizarmos o comando print, não será feita quebra
de linha após a exibição da mensagem, permitindo que o usuário digite os
dados na mesma linha em que a mensagem é exibida.
Nas linhas 10, 12 e 14, usamos o objeto Scanner entrada para ler os
dados solicitados. Na linha 10, é lido do console o valor da variável código,
que é do tipo int. Então, usamos o comando entrada.nextInt(). Já na
linha 12, é lido o valor a ser armazenado na variável nome, que é do tipo
String. Então, usamos o comando entrada.next() para ler esse tipo de
dado. Finalmente, na linha 14, lemos um valor double para a variável preço
utilizando o comando entrada.nextDouble().
Uma vez que os valores forem lidos, usamos comandos System.out.
println para exibir esses dados no console para o usuário (linhas 16 a 19).
O comando System.out.println faz com que seja inserida uma quebra de
linha depois que o texto da mensagem é exibido na tela.

Os comandos nextX da classe Scanner podem causar erros de


execução no programa caso um tipo de dado compatível não seja
fornecido pelo usuário. Um comando nextInt() gera erro caso um valor inteiro
não seja fornecido. Da mesma forma, um comando nextDouble() pode gerar
um erro de execução caso um valor double não seja fornecido. Também é
importante saber que o comando next() lê apenas a primeira palavra digitada
no console (antes de espaços e tabulações, por exemplo). Por isso, para ler frases
contendo esses caracteres, usamos o comando nextLine().

Referências
ORACLE. The Java™ tutorials. Austin: Oracle, c2021. Disponível em: https://docs.oracle.
com/javase/tutorial/essential/io/index.html. Acesso em: 19 jul. 2021.
SCHILDT, H. Java para iniciantes: crie, compile e execute programas Java rapidamente.
6. ed. Porto Alegre: Bookman, 2015.
UNICODE. [Site oficial]. Mountain View: The Unicode Consortium, c2021. Disponível em:
https://home.unicode.org/. Acesso em: 20 jul. 2021.
10 Comandos de entrada e saída

Os links para sites da web fornecidos neste capítulo foram todos


testados, e seu funcionamento foi comprovado no momento da
publicação do material. No entanto, a rede é extremamente dinâmica; suas
páginas estão constantemente mudando de local e conteúdo. Assim, os edito-
res declaram não ter qualquer responsabilidade sobre qualidade, precisão ou
integralidade das informações referidas em tais links.

Você também pode gostar