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. А відтепер ви зможете це робити більш осмислено.