Oi! A lição de hoje será dividida em duas partes por conveniência. Repetiremos alguns tópicos antigos que abordamos anteriormente e consideraremos alguns novos recursos :) Vamos começar com o primeiro. Você já teve uma aula como
BufferedReader
muitas vezes. Espero que você não tenha tido tempo de esquecer esta afirmação:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Antes de continuar a leitura, tente lembrar pelo que cada componente — System.in
, InputStreamReader
, BufferedReader
— é responsável e por que é necessário. Você se lembrou? Se não, não se preocupe. :) Se você esqueceu alguma coisa, releia esta lição , que é dedicada às aulas de leitura. Vamos relembrar brevemente o que cada um deles pode fazer. System.in
— este é um fluxo para receber dados do teclado. Em princípio, bastaria apenas implementar a lógica necessária para ler o texto. Mas, como você deve se lembrar, System.in
só pode ler bytes, não caracteres:
public class Main {
public static void main(String[] args) throws IOException {
while (true) {
int x = System.in.read();
System.out.println(x);
}
}
}
Se executarmos este código e inserirmos a letra cirílica "Й", a saída será:
Й
208
153
10
Os caracteres cirílicos ocupam 2 bytes na memória e são exibidos na tela. O número 10 é a representação decimal de um caractere de alimentação de linha, ou seja, de pressionar Enter. Ler bytes é um prazer, então usar System.in
não é muito conveniente. Para ler corretamente as letras cirílicas (e outras), usamos InputStreamReader
como invólucro:
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);
}
}
}
Entramos com a mesma letra "É", mas desta vez o resultado é diferente:
Й
1049
10
InputStreamReader
converteu dois bytes (208 e 153) no número único 1049. Isso é o que significa ler caracteres. 1049 corresponde à letra cirílica "Й". Podemos facilmente nos convencer de que isso é verdade:
public class Main {
public static void main(String[] args) throws IOException {
char x = 1049;
System.out.println(x);
}
}
Saída do console:
Й
E como forBufferedReader
(e em geral, BufferedAnythingYouWant
), as classes em buffer são usadas para otimizar o desempenho. Acessar uma fonte de dados (arquivo, console, recurso da Web) é bastante caro em termos de desempenho. Portanto, para reduzir o número de acessos, BufferedReader
lê e acumula dados em um buffer especial e os obtemos a partir daí. Como resultado, o número de vezes que a fonte de dados é acessada é reduzido — possivelmente em várias ordens de grandeza! Outra BufferedReader
característica do , e sua vantagem sobre o comum , é o método InputStreamReader
extremamente útil , que lê linhas inteiras de dados, não números individuais. readLine()
Isso, é claro, é super conveniente ao lidar com textos grandes. Veja como são as linhas de leitura:
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 ("The user entered the following text:");
System.out.println(s);
reader.close();
}
}
BufferedReader+InputStreamReader is faster than InputStreamReader alone
The user entered the following text:
BufferedReader+InputStreamReader is faster than InputStreamReader alone
Claro, BufferedReader
é muito flexível. Você não está limitado a trabalhar com o teclado. Por exemplo, você pode ler dados diretamente da web, simplesmente passando a URL necessária para um leitor:
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("https://www.oracle.com/index.html");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
Você pode ler dados de um arquivo passando o caminho do arquivo:
public class Main {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("testFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
String str;
while ((str = reader.readLine()) != null) {
System.out.println (str);
}
reader.close();
}
}
Substituindo System.out
Agora vamos dar uma olhada em um recurso interessante que não abordamos antes. Como você certamente se lembra, aSystem
classe tem dois campos estáticos — System.in
e System.out
. Esses irmãos gêmeos são objetos de fluxo. System.in
é um InputStream
. E System.out
é um PrintStream
. Agora, vamos falar sobre System.out
. Se entrarmos no System
código-fonte da classe, veremos isso:
public final class System {
……………...
public final static PrintStream out = null;
…………
}
Portanto, System.out
é simplesmente uma variável estática comum daSystem
classe. Não há nada de mágico nisso :) A out
variável é uma PrintStream
referência. Aqui está uma pergunta interessante: quando System.out.println()
é executado, por que exatamente a saída vai para o console e não para outro lugar? E isso pode ser mudado de alguma forma? Por exemplo, suponha que queremos ler dados do console e gravá-los em um arquivo de texto. É possível de alguma forma implementar isso simplesmente usando, System.out
em vez de classes adicionais de leitor e escritor? De fato, é :) E podemos fazer isso mesmo que a System.out
variável esteja marcada com o final
modificador! Então, o que precisamos para fazer isso acontecer? Em primeiro lugar, precisamos de um novo PrintStream
objeto para substituir o atual. O objeto atual, definido noSystem
class por padrão, não atende aos nossos propósitos: aponta para o console. Você precisa criar um novo que aponte para um arquivo de texto — o "destino" de nossos dados. Em segundo lugar, precisamos entender como atribuir um novo valor à System.out
variável. Você não pode usar um operador de atribuição simples, porque a variável está marcada como final
. Vamos trabalhar para trás a partir do final. Acontece que a System
classe tem o método que precisamos: setOut()
. Ele pega um PrintStream
objeto e o define como o destino da saída. Isso é exatamente o que precisamos! Tudo o que resta é criar um PrintStream
objeto. Isso também é fácil:
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
O código completo ficará assim:
public class SystemRedirectService {
public static void main(String arr[]) throws FileNotFoundException
{
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
/* Save the current value of System.out in a separate variable so that later
we can switch back to console output */
PrintStream console = System.out;
// Assign a new value to System.out
System.setOut(filePrintStream);
System.out.println("This line will be written to the text file");
// Restore the old value of System.out
System.setOut(console);
System.out.println("But this line will be output to the console!");
}
}
Como resultado, a primeira string é gravada no arquivo de texto e a segunda é exibida no console :) Você pode copiar este código para o seu IDE e executá-lo. Abra o arquivo de texto e você verá que a string foi escrita com sucesso lá :) Com isso, nossa lição chegou ao fim. Hoje relembramos como trabalhar com streams e leitores. Nós lembramos como eles diferem um do outro e aprendemos sobre alguns novos recursos do System.out
, que usamos em quase todas as aulas :) Até as próximas aulas!
Mais leitura: |
---|
GO TO FULL VERSION