1. InputStreamReaderaula

Outro recurso interessante dos fluxos é que você pode combinar vários fluxos em cadeias . Um fluxo pode ler dados não apenas de sua fonte de dados interna, mas também de outro fluxo .

Este é um mecanismo muito poderoso em Java, que permite criar cenários complexos de leitura de dados conectando um fluxo a outro. Tal esquema se parece com isso:

Classe InputStreamReader

Quando um programa lê dados de um fluxo de dados, o fluxo de dados, por sua vez, lê os dados de sua fonte de dados, que é outro fluxo de dados ou um arquivo, por exemplo.

Além do mais, cada fluxo de dados não apenas lê e distribui dados, mas também pode transformá-los ou realizar várias operações neles. Um bom exemplo desse "fluxo intermediário" é a InputStreamReaderclasse.

Já conhecemos uma classe chamada FileReader— é uma Readerque lê dados de um arquivo. E InputStreamReaderde onde obtém seus dados? Isso mesmo - de um arquivo InputStream.

Ao criar um InputStreamReaderobjeto, você precisa passar um InputStreamobjeto ou uma de suas classes descendentes. Exemplo:

String src = "c:\\projects\\log.txt";
FileInputStream input = new FileInputStream(src);
InputStreamReader reader = new InputStreamReader(input);

A InputStreamReaderclasse tem todos os métodos que a Readerclasse tem e eles funcionam exatamente da mesma maneira.

A principal diferença entre a InputStreamReaderclasse e, digamos, FileReaderé de onde eles leem os dados. FileReaderlê dados de um arquivo (duh - é por isso que é chamado FileReader), mas InputStreamReaderlê dados de um arquivo InputStream.

Quando você lê um caractere de um FileReaderobjeto usando o read()método, ele, por sua vez, lê dois bytes do arquivo no disco e os retorna como chars.

Quando você lê um caractere de um InputStreamReaderobjeto usando o read()método, ele, por sua vez, lê dois bytes do FileInputStreamobjeto passado para ele, que por sua vez lê os dados do arquivo. O resultado é uma cadeia de chamadas para read()métodos.


2. BufferedReaderclasse

Outra classe interessante que você provavelmente usará muito é BufferedReader. Este também é um "fluxo intermediário" que lê dados de outro fluxo.

Como o próprio nome sugere, a BufferedReaderclasse é uma subclasse de Readere permite que você leia caracteres . Mas o mais interessante é que você também precisa passar para ela uma fonte de dados na forma de um stream a partir do qual os caracteres podem ser lidos , ou seja, um stream que herda a Readerclasse.

Qual é o ponto? Ao contrário de InputStreamReader, a BufferedReaderclasse não converte bytes em caracteres: ela não converte absolutamente nada. Em vez disso, ele armazena os dados em buffer .

Quando um programa lê um único caractere de um BufferedReaderobjeto, o objeto lê uma grande variedade de caracteres de seu fluxo de origem de uma só vez. E os armazena internamente.

Quando o próximo caractere é lido do BufferedReaderobjeto, ele simplesmente pega o próximo caractere de sua matriz de buffer interno e o retorna sem acessar a fonte de dados. Somente quando todos os caracteres no buffer são usados, ele lê em outra grande matriz de caracteres.

A BufferedReaderclasse também tem um método muito útil — String readLine(), que permite ler sequências inteiras de dados do fluxo de origem de uma só vez. Você pode usar esse método para, digamos, ler um arquivo e exibir seu conteúdo na tela linha por linha. Exemplo:

Escrevemos especificamente um código compacto para ilustrar como isso pode ser conveniente. Esse código também poderia ser escrito com um pouco mais de detalhes.

String src = "c:\\projects\\log.txt";

try(FileReader in = new FileReader(src);
BufferedReader reader = new BufferedReader(in))
{
   while (reader.ready())
   {
      String line = reader.readLine();
      System.out.println(line);
   }
}
Crie um FileReaderobjeto. A fonte de dados é um arquivo.
Crie um BufferedReaderobjeto. A fonte de dados é um arquivo FileReader.
Enquanto ainda houver dados no leitor
Leia uma linha
Exiba a linha
Um ponto importante:

Se você encadear vários fluxos, o close()método só precisará ser chamado em um deles. Esse fluxo chamará o método em sua fonte de dados e assim por diante, até close()ser chamado no fluxo de dados final.



3. Lendo no console

E mais um fato interessante: a Scannerclasse nada mais é do que um fluxo de entrada intermediário que lê dados de System.in, que também é um fluxo de dados.

Aqui estão duas maneiras de ler uma linha do console:

classe do scanner Classes BufferedReader e BufferedWriter
InputStream stream = System.in;
Scanner console = new Scanner(stream);
String line = console.nextLine();
InputStream stream = System.in;
InputStreamReader reader = new InputStreamReader(stream);
BufferedReader buff = new BufferedReader(reader);
String line = buff.readLine();

Nosso amigo nada mais é do que uma variável estática da classe. É um cujo nome é .System.ininSystemInputStreamin

Assim, quase desde o início de seus estudos de Java no CodeGym, você trabalhou com fluxos de dados e construiu cadeias a partir deles. Mas agora você fará isso de forma mais consciente.