CodeGym /Blogue Java /Random-PT /Leitura do teclado: "leitores"
John Squirrels
Nível 41
San Francisco

Leitura do teclado: "leitores"

Publicado no grupo Random-PT
Oi! As lições e tarefas do Nível 3 ensinaram como exibir itens no console e, indo na outra direção, como ler dados do teclado.
Leitura do teclado: "leitores" - 1
Você até aprendeu a usar a seguinte construção complexa para fazer isso:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Mas há uma pergunta que ainda não respondemos.

Como no mundo isso funciona?

Na realidade, os programas raramente são totalmente independentes. Eles se comunicam com outros programas, sistemas, Internet, etc. Por "comunicar", queremos dizer principalmente "trocar dados". Ou seja, eles recebem alguns dados externos e também enviam dados internos do programa para algum lugar. Exemplos de programas que trocam dados são abundantes na vida cotidiana. Por exemplo, muitos sites permitem que você faça login usando sua conta do Facebook ou Twitter em vez de se registrar. Nessa situação, dois programas (por exemplo, o Twitter e o site no qual você está entrando) trocam os dados necessários. O resultado final é que você está conectado com sucesso. A palavra "stream"é usado para descrever o processo de troca de dados. De onde veio esse nome? Em sua experiência, um "córrego" pode estar mais associado a rios e do que a programação. Isso não é por acaso :) Um fluxo é, em essência, um dado em movimento. Em outras palavras, na programação, não é a água que flui, mas sim os dados na forma de bytes e caracteres. Podemos receber bits de dados de um fluxo de dados e usá-los. Mais uma vez, usaremos a analogia água/fluxo: você pode colher água de um rio para fazer sopa, apagar o fogo ou regar suas flores. Os fluxos permitem que você trabalhe com qualquer fonte de dados: seja a Internet, o sistema de arquivos do seu computador ou qualquer outra coisa — não faz diferença. Streams são uma ferramenta universal. Eles permitem que um programa receba dados de qualquer lugar (fluxos de entrada) e os envie para qualquer lugar (fluxos de saída). A tarefa deles é a mesma: pegar dados de um lugar e enviá-los para outro. Existem dois tipos de fluxos:
  1. Fluxos de entrada são usados ​​para receber dados
  2. Fluxos de saída são para enviar dados.
Em Java, esses fluxos são implementados pelas classes InputStreame OutputStream. Mas os fluxos podem ser categorizados de outra maneira. Além dos fluxos de entrada e saída, também falamos de fluxos de bytes e fluxos de caracteres . O significado aqui deve ser bastante claro: o fluxo de bytes envia informações como um conjunto de bytes, enquanto um fluxo de caracteres as envia como um conjunto de caracteres. Nesta lição, abordaremos os fluxos de entrada. Colocarei um link com informações sobre fluxos de saída no final da lição. Você pode ler por conta própria :) Agora dê uma olhada neste código:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Ao passar pelas aulas, você não achou essa linha bastante intimidadora? :) Esse não será o caso depois de explorarmos como funciona. Vamos consertar as coisas. Começaremos pelo final. System.iné um InputStreamobjeto, uma instância da classe da qual falamos anteriormente. É um fluxo de entrada vinculado a um dispositivo de entrada do sistema (o teclado). A propósito, você está indiretamente familiarizado com este fluxo. Afinal, você costuma usar seu "colega de trabalho" — System.out! System.outé o fluxo de saída do sistema . Ele é usado para enviar dados para o console por meio de seu método favorito System.out.println(), que você usa constantemente :) System.outé um fluxo para enviar dados para o console, enquantoSystem.iné para obter dados do teclado. É tudo simples :) Além do mais, podemos ler dados do teclado sem essa enorme construção. Podemos simplesmente escrever: System.in.read();

public class Main {

   public static void main(String[] args) throws IOException {

       while (true) {
           int x = System.in.read();
           System.out.println(x);
       }
   }
}
A InputStreamclasse (lembre-se, System.iné um InputStreamobjeto) tem um read()método que permite ler dados. Há um problema: ele lê bytes , não caracteres . É chato usar apenas letras em inglês, então vamos tentar ler o caractere chinês "魚" no teclado (basta copiar esta letra daqui e colá-la no console usando ctrl + v no PC ou Command + v no Mac). A propósito, esse personagem significa 'um peixe'. Saída do console: 233 173 154 10 Este símbolo e muitos outros chineses ocupam 3 bytes na memória do computador (ao contrário das letras latinas, que ocupam apenas 1 byte). Neste caso, 4 bytes são lidos do stream: os três primeiros representam o caractere "魚", e o outro byte representa uma nova linha (Enter). Assim, System.inem sua forma simples não é uma opção para nós. Humanos (com raras exceções!) não sabem ler bytes. Mas a InputStreamReaderclasse vem para o resgate! Vamos ver que tipo de animal é esse.

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
Passamos System.inpara o objeto InputStreamReader . O nome da classe diz isso! Criamos um InputStreamReaderobjeto e passamos a ele um fluxo de entrada do qual ele lerá os dados. Nesse caso...

new InputStreamReader(System.in)
...nós dizemos, "você lerá os dados do fluxo de entrada do sistema (do teclado)". Mas esta não é sua única função! O InputStreamReadernão recebe apenas dados do stream. Ele também converte fluxos de bytes em fluxos de caracteres . Em outras palavras, você não precisa mais converter os dados de "uns e zeros" para uma "linguagem legível por humanos". InputStreamreaderfaz tudo por você. Claro, InputStreamReadernão se limita à leitura de dados do console. Ele também pode ler dados de outros lugares. Por exemplo, de um arquivo:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

   public static void main(String[] args) throws IOException {
       InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("C:\\Users\\username\\Desktop\\testFile.txt"));
   }
}
Aqui criamos um FileInputStream(um tipo de InputStream), passamos o caminho do arquivo e passamos o próprio stream para o arquivo InputStreamReader. Agora ele poderá ler os dados do arquivo (se realmente existir um arquivo no caminho, é claro). Também usamos o método InputStreamReaderda classe read()para ler dados (a fonte dos dados não importa: o console, um arquivo ou outro lugar). Qual é a diferença entre System.in.read()e InputStreamReader.read()?\ Vamos novamente tentar ler o caractere "魚" com um InputStreamReader. Relembro o que realmente foi lido por System.in.read(): 233 173 154 10 E como funciona InputStreamReadero mesmo?

public class Main {

   public static void main(String[] args) throws IOException {

       InputStreamReader reader = new InputStreamReader(System.in);
       while (true) {
           int x = reader.read();
           System.out.println(x);
       }
   }
}
Saída do console: 39770 10 A diferença é imediatamente aparente. O último byte (que representa a nova linha) permanece inalterado (o número 10), mas o caractere "魚" foi convertido em um único código "39770". Isso é o que significa ler caracteres! Se você não acredita que 39770 representa a letra "魚", é fácil se convencer :)
import java.io.IOException;

public class Main {

   public static void main(String[] args) throws IOException {

       char x = 39770;
       System.out.println(x);
   }
}
Saída do console: Mas se InputStreamReaderé tão bom, por que também precisamos BufferedReader? InputStreamReadersabe como ler dados e converter bytes em caracteres. O que mais poderíamos pedir? Por que outro Leitor? :/ A resposta é muito simples: para maior desempenho e comodidade . Vamos começar com o desempenho. Ao BufferedReaderler os dados, ele usa uma área especial chamada buffer, onde "armazena" os caracteres que lê. Por fim, quando esses caracteres forem necessários no programa, eles serão retirados do buffer, não diretamente da fonte de dados (teclado, arquivo, etc.). Isso economiza muitos recursos. Para entender como isso funciona, imagine um mensageiro em uma grande empresa. O mensageiro está sentado em um escritório, esperando que alguém traga os pacotes para entrega. Cada vez que recebe um novo pacote, ele pode pegar a estrada imediatamente. Mas pode haver muitos pacotes durante o dia. Ele teria que fazer muitas viagens entre o escritório e os endereços de entrega. Em vez disso, o mensageiro coloca uma caixa em seu escritório. Todos colocam seus pacotes na caixa. Agora o correio pode pegar a caixa com calma e passar de um endereço para outro. Isso economiza muito tempo, porque ele não precisa voltar ao escritório todas as vezes. Neste exemplo, a caixa é apenas um buffer e o escritório é uma fonte de dados. É muito mais fácil para o correio retirar pacotes de uma única caixa ao fazer entregas do que voltar ao escritório todas as vezes. Ele também economizará gasolina. Da mesma forma, em um programa, é muito menos intensivo em recursos obter dados de um buffer do que referir-se à fonte de dados a cada vez. Como resultado,BufferedReader+ InputStreamReaderé mais rápido do que InputStreamReadersozinho . Nós consideramos o desempenho. E a conveniência? A principal vantagem é que Bufferedreaderpode ler dados não apenas um caractere por vez (embora possa fazer isso com seu read()método), mas também linhas inteiras por vez! Isso é feito usando o readLine()método;

public class Main {

   public static void main(String[] args) throws IOException {

       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
       String s = reader.readLine();
       System.out.println("We read this line from the keyboard:");
       System.out.println(s);
   }
}
Saída do console: CodeGym é o melhor site para aprender Java! Lemos esta linha do teclado: CodeGym é o melhor site para aprender Java! Isso é especialmente útil ao ler grandes quantidades de dados. A leitura de uma ou duas linhas de texto, caractere por caractere, ainda é possível. Mas ler em "Guerra e Paz" uma letra de cada vez seria um tanto problemático :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION