Streams: Standard IO

Computação II - Ciência da Computação


Prof.: Danilo S. Carvalho

Nessa aula, vamos compreender um pouco melhor sobre os mecanismos de entrada e saída padrão do Java.


Ao final da aula, teremos uma visão mais clara sobre os fluxos de dados (streams) básicos e como se organizam.

Até esse momento, utilizamos frequentemente o System.out e System.in para ler e escrever dados no terminal.


Mas ainda não paramos para entender como eles funcionam e o que mais podemos fazer com eles.


Faremos isso agora, dando o primeiro passo rumo à compreensão dos fluxos de entrada e saída da linguagem Java.

Relembrando: a classe System fornece várias ferramentas para interação do programa com seu ambiente de execução.

Isso é feito através de campos e métodos static, uma vez que a classe não é instanciável (pois possui apenas construtores privados) e não pode ser herdada (final).

Desses campos podemos destacar in e out, que fornecem acesso à entrada e saída padrão do sistema, respectivamente.

Cada um desses campos pertence a um subtipo diferente de um conceito conhecido em Java como fluxo (de dados).

Um fluxo possui uma origem e um destino para os dados que nele são transferidos.

Quando a origem dos dados é externa ao programa, queremos trazer os dados para manipulá-los dentro do programa. Portanto o fluxo é de entrada.

Quando a origem dos dados é interna ao programa, queremos levar os dados para fora do programa, de forma a comunicar um resultado ou tornar persistente uma mudança feita em memória volátil. Portanto o fluxo é de saída.

O campo System.in é do tipo InputStream, o fluxo de entrada mais abstrato em Java (e uma classe abstrata de fato). É portanto uma instância de uma subclasse concreta qualquer de fluxo de entrada.

Quando iniciamos um programa, esse campo é inicializado por padrão para uma instância que representa a entrada padrão do sistema. A entrada padrão tem como principal meio de acesso o terminal interativo do sistema.

Por ser o tipo mais abstrato de fluxo de entrada, o InputStream não faz suposições sobre os dados a serem transferidos, e oferece apenas métodos para ler e pular bytes, verificar disponibilidade da entrada, e encerrar o fluxo de dados.

Portanto, precisaremos de alguma outra classe para poder interpretar e manipular os dados vindos dessa entrada.

A escolha que usamos até então foi a classe Scanner (java.util), que é instanciada para um certo fluxo de entrada, e interpreta o conteúdo desse fluxo de acordo com a chamada de seus métodos (ex: nextDouble()).

Além do terminal, podemos redirecionar a saída de um outro programa qualquer para a entrada padrão do nosso programa.

Isso traz uma grande flexibilidade quanto ao que podemos trazer como entrada, mas também implica em maior complexidade para tratar o fluxo de dados.

A classe Scanner possui uma variedade de métodos para nos ajudar a interpretar o fluxo de entrada escolhido.

Por fim, a classe System nos permite redefinir o campo in para um outro fluxo de entrada, que veremos nas próximas aulas. Isso é feito através do método setIn().

O campo System.out é do tipo PrintStream, um tipo de fluxo de saída responsável por formatar os dados de outros fluxos de saída. Faz parte da hierarquia de classes do OutputStream, o fluxo de saída mais abstrato em Java.

Quando iniciamos um programa, esse campo é inicializado por padrão para uma instância que representa a saída padrão do sistema. A saída padrão tem como principal destino o terminal interativo do sistema.

O PrintStream assume que queremos escrever texto formatado no destino, logo todos os dados direcionados a esse tipo de fluxo serão convertidos em uma sequência de caracteres.

Os dados são passados ao fluxo através dos métodos append, format, print, println, e write, que diferem na maneira como escrevem os dados e no tipo de dado que recebem.

Da mesma forma que o campo in, a classe System nos permite redefinir o campo out para direcionar a saída para outro PrintStream.

Além disso, um PrintStream pode ser instanciado para utilizar qualquer OutputStream como destino, permitindo encadear fluxos de dados para escrever em um arquivo por exemplo.

Agora sabemos um pouco mais sobre os mecanismos de entrada e saída padrão em Java.


Os fluxos de dados que estudamos nessa aula serão fundamentais para entendermos os demais fluxos encontrados na linguagem, e também a idéia de persistência dos dados.


Links importantes para consultar:

Perguntas:

  1. Como podemos saber se um fluxo de entrada padrão chegou ao fim?
  2. Qual é a superclasse de PrintStream e seu conceito?

Exercício:

  1. Redirecione um arquivo fonte java para a entrada padrão do seu programa e conte quantas variáveis do tipo String e do tipo int foram declaradas no fonte lido.

Exemplo (Linux):

                    
                        cat UmaClasse.java | java MeuPrograma
                        4 String(s), 2 int(s)
                    
                

Até a próxima aula!