1. Класс InputStreamReader
Еще одной интересной особенностью потоков является возможность объединять несколько потоков в цепочки. Поток может читать данные не только из источника данных, который их хранит, но из другого потока.
Это очень мощный механизм в Java, который позволил конструировать сложные сценарии чтения данных, соединяя одни потоки с другими. Выглядит такая схема примерно так:
Когда программа читает данные из потока данных, он в свою очередь читает их из своего источника данных: другого потока данных или из файла, например.
При этом каждый поток данных не просто читает и отдает данные, а еще может преобразовывать их или выполнять над ними различные операции. Хорошим примером такого «промежуточного потока» данных является класс InputStreamReader
.
Мы уже знаем класс, который называется FileReader
, и это Reader
, который читает данные из файла. А откуда читает данные класс InputStreamReader
? Правильно: из потока InputStream
.
Чтобы создать объект типа InputStreamReader
, в него нужно передать объект типа InputStream
, или его класса наследника. Пример:
String src = "c:\\projects\\log.txt";
FileInputStream input = new FileInputStream(src);
InputStreamReader reader = new InputStreamReader(input);
У класса InputStreamReader
есть все методы, которые есть у класса Reader
, причем они работают точно так же.
Основное отличие классов InputStreamReader
и, например, FileReader
в том, откуда они читают данные. FileReader
читает данные из файла (поэтому он и называется FileReader
), а InputStreamReader
читает данные из потока InputStream
.
Когда вы читаете символ из объекта FileReader
с помощью метода read()
, он в свою очередь читает из файла на диске два байта и возвращает их вам как char
.
Когда вы читаете символ из объекта InputStreamReader
с помощью метода read()
, он в свою очередь читает два байта из переданного в него объекта FileInputStream
, который в свою очередь читает данные из файла. Получается такая цепочка вызовов методов read()
.
2. Класс BufferedReader
Есть еще один интересный класс, который вы, скорее всего, будете часто использовать — BufferedReader
. Это тоже «промежуточный поток», который читает данные из другого потока.
Класс BufferedReader
, как видно из его названия, является классом-наследником от Reader
и позволяет читать символы. Однако, что самое интересное, в качестве источника данных в него тоже нужно передать поток, из которого можно читать символы – поток-наследник от класса Reader
.
В чем же смысл? В отличие от InputStreamReader
’а, класс BufferedReader
не преобразовывает байты в символы: он вообще ничего не преобразовывает. Вместо этого он буферизует данные.
Когда программа читает из объекта BufferedReader
один символ, он читает из своего потока-источника сразу большой массив символов. И сохраняет их у себя внутри.
При чтении следующего символа из объекта BufferedReader
, он просто возьмет очередной символ из своего внутреннего массива-буфера и отдаст его, не обращаясь при этом к потоку-источнику данных. И только когда все символы в буфере закончатся, он снова прочитает большой массив символов.
Еще у класса BufferedReader
есть очень полезный метод — String readLine()
, который позволяет читать данные из потока-источника сразу строками. С помощью этого метода можно, например, прочитать какой-то файл и вывести его содержимое на экран построчно. Пример:
Мы специально записали код в компактном формате, чтобы вы увидели, как это может быть удобно. Можно записать данный код и немного более детально.
|
Создаем объект FileReader , источник данных — файл.Создаем объект BufferedReader , источник данных — объект FileReader ;пока в reader еще есть данныеПрочитать одну линию Вывести линию на экран |
Если вы соединили несколько потоков в цепочку, метод close()
достаточно вызвать только у одного из них: он вызовет его у своего источника данных и т.д., пока не дойдут до финального потока с данными.
3. Чтение с консоли
И еще один интересный факт: класс Scanner
— ничто иное как входящий промежуточный поток данных, который читает их из потока System.in
— тоже потока данных.
Вот два способа чтения строки с консоли:
Класс Scanner | Классы BufferedReader и InputStreamReader |
---|---|
|
|
Наш знаменитый System.in
— это ничто иное как статическая переменная in
класса System
. Тип ее — InputStream
, а имя — in
.
Так что практически с самого начала изучения Java на JavaRush вы работаете с потоками данных и строите из них цепочки. Только теперь вы будете это делать более осознанно.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ