1. Клас OutputStream
З потоками вводу ми щойно розібралися. Тепер саме час поговорити про потоки виводу.
Клас OutputStream
є батьківським класом для всіх класів, які підтримують байтове виведення. Це абстрактний клас, який сам нічого не робить: для цього є класи-спадкоємці на всі випадки.
Дещо складно, чи не так? Якщо простіше, цей клас працює з байтами, а не, скажімо, із символами чи іншими типами даних. А термін «абстрактний клас» означає, що зазвичай використовується не цей клас, а класи-спадкоємці, наприклад FileOutputStream
і подібні.
Але повернемося до класу OutputStream
. Цей клас має методи, що їх зобов'язані реалізовувати всі його класи-спадкоємці. Перелічимо основні з них:
Методи | Опис |
---|---|
|
Записує один байт (не int ) у потік. |
|
Записує масив байтів у потік |
|
Записує частину масиву байтів у потік |
|
Записує в потік усі дані, які є в буфері |
|
Закриває потік |
Під час створення об'єкта класу-спадкоємця InputStream
зазвичай указується об'єкт-джерело, з якого InputStream
читає дані. Під час створення об'єкта класу-спадкоємця OutputStream
також зазвичай указується цільовий об'єкт або цільовий потік, в який будуть записуватися дані.
Побіжно перегляньмо всі методи класу OutputStream
:
Метод write(int b)
Цей метод записує в потік виводу один байт (не int
). Передане значення перетворюється на байтовий тип, три перші байти відкидаються.
Метод write(byte[] buffer)
Записує в потік виводу переданий масив байтів.
Метод write(byte[] buffer, int offset, int length)
Записує в потік виводу частину переданого масиву байтів. Змінна offset
задає номер першого елемента масиву, length
— довжину записуваного фрагмента.
Метод flush()
Метод flush()
використовується для примусового запису в цільовий потік таких даних, які можна кешувати в цьому потоці. Застосовується в разі використання буферизації та/або декількох об'єктів-потоків, об'єднаних у ланцюжок.
Метод close()
Записує в цільовий об'єкт усі незаписані дані. У разі використання оператора try
-with-resources метод close()
можна не викликати.
Приклад: копіювання файлу
Код | Примітка |
---|---|
|
InputStream для читання з файлуOutputStream для запису у файлБуфер, в який зчитуються дані Доки в потоці є дані Зчитуємо дані в буфер Записуємо дані з буфера в другий потік |
2. Клас Writer
Клас Writer
— це повний аналог класу OutputStream
, тільки він працює не з байтами, а із символами — char
.
Це абстрактний клас: об'єкти класу Writer
створити неможливо. Його головне призначення — бути єдиним батьківським класом для сотень класів-спадкоємців і передати їм спільні методи роботи із символьними потоками.
Методи класу Writer
(і всіх його класів-спадкоємців):
Методи | Опис |
---|---|
|
Записує один символ (не int ) у потік. |
|
Записує масив символів у потік |
|
Записує частину масиву символів у потік |
|
Записує рядок у потік |
|
Записує частину рядка в потік |
|
Записує в потік усі дані, які є в буфері |
|
Закриває потік |
Методи дуже схожі на методи класу OutputStream
, тільки працюють не з байтами, а із символами.
Короткий опис методів:
Метод write(int b)
Цей метод записує в потік виводу один символ char
(не int
). Передане значення перетворюється на тип char
, два перші байти відкидаються.
Метод write(char[] buffer)
Записує в потік виводу переданий масив символів.
Метод write(char[] buffer, int offset, int length)
Записує в потік виводу частину переданого масиву символів. Змінна offset
задає номер першого елемента масиву, length
— довжину записуваного фрагмента.
Метод write(String str)
Записує в потік виводу переданий рядок.
Метод write(String str, int offset, int length)
Записує в потік виводу частину переданого рядка й перетворює рядок на масив символів. Змінна offset
задає номер першого елемента масиву, length
— довжину записуваного фрагмента.
Метод flush()
Метод flush()
використовується для примусового запису в цільовий потік таких даних, які можна кешувати в цьому потоці. Застосовується в разі використання буферизації та/або декількох об'єктів-потоків, об'єднаних у ланцюжок.
Метод close()
Записує в цільовий об'єкт усі незаписані дані. У разі використання оператора try
-with-resources метод close()
можна не викликати.
Приклад програми, яка копіює текстовий файл:
Код | Примітка |
---|---|
|
Reader для читання з файлуWriter для запису у файлБуфер, в який зчитуються дані Доки в потоці є дані Зчитуємо дані в буфер Записуємо дані з буфера в другий потік |
Класс StringWriter
StringWriter
— це ще один цікавий клас-спадкоємець класу Writer
. Він містить змінюваний рядок — об'єкт StringBuffer
. І щоразу, коли ви щось «пишете» в об'єкт StringWriter
, текст просто додається у внутрішній буфер.
Приклад:
Код | Примітка |
---|---|
|
Створюється цільовий символьний потік StringWriter Рядок записується в буфер усередині StringWriter Рядок записується в буфер усередині StringWriter Перетворюємо вміст об'єкта на рядок |
У цьому коді клас StringWriter
по суті є обгорткою класу StringBuffer
, однак клас StringWriter
— це спадкоємець класу-потоку Writer
і може використовуватися в ланцюжках з об'єктів-потоків. Доволі корисна властивість на практиці.
3. Клас PrintStream
Класи потокового виводу теж можна об'єднувати в ланцюжки з використанням потоків-посередників, які записують дані в переданий їм цільовий потік. Загальна схема взаємодії цих потоків така:
PrintStream
— це найцікавіший з усіх проміжних потоків виводу, який до того ж має найбільше функцій. Він має кілька десятків методів і аж 12 конструкторів.
Клас PrintStream
є спадкоємцем класу FilterOutputStream
, а той — спадкоємцем класу OutputStream
. Тому клас PrintStream
має всі методи батьківських класів і до того ж свої власні. Наведемо найцікавіші з них:
Методи | Опис |
---|---|
|
Перетворює переданий об'єкт на рядок і виводить у цільовий потік. |
|
Перетворює переданий об'єкт на рядок і виводить у цільовий потік. В кінці додає символ розриву рядка. |
|
Виводить у цільовий потік символ розриву рядка. |
|
Конструює та виводить рядок на основі рядка-шаблону й переданих аргументів подібно до методу String.format() . |
А де ж кілька десятків методів, запитаєте ви?
Річ у тім, що цей клас має багато варіантів методів print()
і println()
з різними аргументами, які вже описано в таблиці вище.
Ми навіть не розглядатимемо ці методи, тому що ви їх і так вже добре знаєте. Здогадуєтеся, до чого я хилю?
Пам'ятаєте команду System.out.println()
? Її можна записати у два рядки:
Код | Виведення на екран |
---|---|
|
|
Наша улюблена команда System.out.println()
— це виклик методу println()
для статичної змінної out
класу System
. І ця змінна має тип PrintStream
.
На всіх попередніх рівнях ви майже в кожній задачі викликали методи класу PrintStream
і навіть не здогадувалися про це!
Практичне використання
У мові Java є один цікавий клас — ByteArrayOutputStream
, успадкований від OutputStream
, і цей клас, власне, є масивом байтів, що динамічно збільшується.
Об'єкт ByteArrayOutputStream
і об'єкт PrintStream
можна об'єднати в такий ланцюжок:
Код | Опис |
---|---|
|
Створили в пам'яті буфер для запису Обгорнули буфер об'єктом PrintStream Записали дані як у консоль Перетворили масив на рядок! Виведення на екран:
|
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ