Назад Зміст Вперед

1.1. Байтові потоки. Ієрархія

Кожна програма повинна записувати свої дані в місце зберігання або канал, і кожна програма повинна зчитувати дані з каналу або місця зберігання. У Java, ці канали, куди програми записують і звідки програми зчитують дані, називаються Потоками (Stream).

Кожен потік запису даних, містить набір методів запису. І кожен потік зчитування даних, відповідно має подібний набір методів читання. Як тільки потік створюється, всі ці методи повинні бути викликані.

Потік пов'язаний з фізичним пристроєм за допомогою системи вв/вив java. Всі потоки поводяться однаково, навіть незважаючи на те, що реальні фізичні пристрої, до яких вони підключені, відрізняються один від одного. Таким чином, одні й ті ж класи і методи вв/вив застосовні до пристроїв різного типу. Це означає, що абстракція вхідного потоку може охопити різні типи введення: з дискового файлу, клавіатури або мережного сокета (Сокети (англ. socket - заглиблення, гніздо, роз'єм) — назва програмного інтерфейсу для забезпечення обміну даними між процесами. Процеси при такому обміні можуть виконуватися як на одній ЕОМ, так і на різних ЕОМ, пов'язаних між собою мережею. Сокет - абстрактний об'єкт, що представляє кінцеву точку з'єднання).

Аналоrічно вихідний потік може посилатися на консоль, дисковий файл або підключення до мережі. Потоки - це зрозумілий спосіб поводження з вв/вив без необхідності для вашоrо коду розбиратися з різницею, наприклад, між клавіатурою і мережею. Jаvа реалізує потоки всередині ієрархії класів, визначених в пакеті java.ioДля використання класів потоків необхідно імпортувати пакет java.io.

В Java визначені два типи потоків (Stream): Байтовий та Символьний

Stream

                         Байтовий потік

Символьний потік

Байтові потоки представляють зручні засоби для управління введенням і виведенням байтів. Використовуються, наприклад, при читанні і записі бінарних даних. Символьні потоки пропонують зручні можливості управління введенням і виведенням символів. Вони використовують кодування Unicode і, таким чином, можуть бути інтернаціоналізовані. Крім того, в деяких випадках символьні потоки більш ефективні, ніж байтові. Вихідна версія java (java 1.0) не включала символьних потоків, і тому весь вв/вив був байт-орієнтованим. Символьні потоки були додані в java 1.1, і при цьому деякі байт-орієнтовані класи і методи застаріли. Ось чому старий код, до якого не використовувалися символьні потоки, повинен бути, де можливо, оновлений, щоб скористатися їх перевагами.

!!! На найнижчому рівні весь вв/вив, як і раніше, байт-орієнтований. Символьні потоки просто пропонують зручні та ефективні засоби управління символами.
Ієрархія класів байтових потоків починається з двох абстрактних класів InputStream та OutputStream. В цих класах визначені методи read() та write(). Ієрархія класів символьних потоків починається з двох абстрактних класів Reader та Writer. В цих класах визначені методи read() та write().
Клас байтового потоку
Пояснення
InputStream
Абстрактний клас, що описує потік вводу
OutputStream
Абстрактний клас, що описує потік виводу
FilterInputStream
Клас, що реалізує абстрактний клас  InputStream
FilterOutputStream
Клас, що реалізує абстрактний клас  OutputStream
BufferedInputStream
Клас буферизованого потоку вводу
BufferedOutputStream
Клас буферизованого потоку виводу
ByteArrayInputStream
Клас потоку вводу для зчитування з масиву
ByteArrayOutputStream
Клас потоку виводу для запису в масив
FileInputStream
Клас потоку вводу для зчитування з файлу
FileOutputStream
Клас потоку виводу для запису в файл
DataInputStream
Клас потоку вводу з методами для зчитування даних стандартних типів Java
DataOutputStream
Клас потоку виводу з методами для запису даних стандартних типів Java
PrintStream
Клас потоку виводу, що підтримує методи print() та println()
Клас символьного потоку
Пояснення
Reader
Абстрактний клас, що описує потік вводу
Writer
Абстрактний клас, що описує потік виводу
FilterReader
Клас, що описує відфільтрований потік вводу
FilterWriter
Клас, що описує відфільтрований потік виводу
InputStreamReader
Клас потоку вводу, що переводить байти в символи
OutputStreamWriter
Клас потоку виводу, що переводить символи в байти
StringReader
Клас потоку вводу для зчитування з рядка
StringWriter
Клас потоку виводу для запису в рядок
FileReader
Клас потоку вводу для зчитування з файлу
FileWriter
Клас потоку виводу для запису в файл
BufferedReader
Клас буферизованого потоку вводу
BufferedWriter
Клас буферизованого потоку виводу
PrintWriter
Клас потоку виводу, що підтримує методи print() та println()
CharArrayReader
Клас потоку вводу для зчитування з масиву
CharArrarWriter
Клас потоку виводу для запису в масив
LineNumberReader
Клас потоку вводу для підрахунку рядків

Клас System

Частина можливостей вводу-виводу може бути реалізована через клас System. Клас System містить три поточних змінних: in, out та err. Це public static поля класу, які є поточними змінними.
System.out – потік стандартного виводу. За умовчанням пов'язаний з консоллю. Об'єкт типу PrintStream.
System.in – потік стандартного вводу. За умовчанням пов'язаний з клавіатурою. Об'єкт типу InputStream.
System.err – cстандартний потік помилок. За умовчанням пов'язаний з консоллю. Об'єкт типу PrintStream.

Консольний ввід

Консольний ввід в Java реалізується через зчитування з об'єкту System.in. При цьому використовується клас BufferedReader – клас буферизованого вхідного потоку (підключення пакету import java.io.*;).
Конструктор: BufferedReader(Reader)
Reader – абстрактний клас, підкласом якого є InputSrtreamReader (перетворює байти в символи)
Конструктор: InputStreamReader(InputStream)
Приклад.
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
Для зчитування символів використовують метод read() класу BufferedReader.
Сигнатура: int read()throws IOException
Для зчитування текстових рядків використовують метод readLine() класу BufferedReader.
Сигнатура: String read()throws IOException
Клас InputStreamReader переводить байти в символи, але дозволяє зчитувати лише один символ. Тому він “вкладається” в клас BufferedReader, який дозволяє зчитувати декілька символів. Для цього символи вхідного потоку заносяться в буфер, звідки зчитуються.

Консольний ввід в JDK 5.0. Клас Scanner

Починаючи з версії JDK 5.0 консольний ввід можна реалізувати через клас Scanner. Підключення пакету import java.util.*;
Загальна схема: на основі стандартного потоку вводу System.in створюється об'єкт класу Scanner, через який реалізується введення даних з консолі.
Деякі методи класу Scanner:
1. nextLine() – зчитування рядка
2. next() – зчитування слова
3. nextInt() – зчитування цілого числа
4. nextDouble() – зчитування дійсного числа

Використання діалогового вікна

Введення даних під час виконання програми можна реалізувати через діалогове вікно, що є елементом класу з бібліотеки Swing. Програма містить інструкцію import javax.swing.*;
Діалогове вікно викликається командою JOptionPane.showInputDialog(String)
   Аргумент – текст, що відображається у вікні
   Результат – текст, що вводиться користувачем в полі вікна
При виклику вікна створюється новий потік, який автоматично не завершується. Для завершення всіх потоків програму закінчуємо інструкцією System.exit(0).
Для перетворення тексту в числа використовують методи
   Integer.parseInt(String)
   Double.parseDouble(String)
Їх аргумент – рядок, що переводиться в числовий формат.

Робота з файлами

Для роботи з файлами використовують класи файлових потоків:
FileInputStream
FileOutputStream
Конструктори класів:
   FileInputStream(String) throws FileNotFoundException
   FileOutputStream throws FileNotFoundException
Виключення FileNotFoundException – файл не знайдено
Після завершення роботи з файлом його треба закрити – для цього використовують метод close()

ПРИКЛАДИ

1. Приклад зчитування символів з консолі:

import java.io.*;
class MySymbInput{
public static void main(String args[]) throws IOException{
char x;
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println(
"Введіть декілька символів і натисніть <Enter>:");
do{
x=(char)br.read();
System.out.println(x);
}while(x!='x');
}
}


Результат:
Введіть декілька символів і натисніть <Enter>:
fgffkj
f
g
f
f
k
j

2. Приклад зчитування текстових рядків:

import java.io.*;
class MyStringInput{
public static void main(String args[]) throws IOException{
String str=
"Ваше замовлення: ";
String s;
int count=0;
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println(
"Що бажаєте:");
s=br.readLine();
while(!s.equalsIgnoreCase("Ні")){
count++;
str=str+"\n"+count+": "+s.toLowerCase();
System.out.println(str+
"\n Ще щось?");
s=br.readLine();}
System.out.println(
"Дякуємо! Ваше замовлення прийнято!");
}
}


Результат:
Що бажаєте:
перше
Ваше замовлення:
1: перше
Ще щось?
друге
Ваше замовлення:
1: перше
2: друге
Ще щось?
ні
Дякуємо! Ваше замовлення прийнято!

3. Приклад використання класу Scanner:

import java.util.*;
class MyNewScanner{
public static void main(String args[]){
Scanner inp=new Scanner(System.in);
String name;
int age;
System.out.println(
"Як Вас Звати?");
name=inp.nextLine();
System.out.println(
"Доброго дня, "+name+"!");
System.out.println(
"Скільки Вам років?");
age=inp.nextInt();
System.out.println(name+
", Вам "+age+" років!");
}
}

Результат:
Як Вас Звати?
Оля
Доброго дня, Оля!
Скільки Вам років?
10
Оля, Вам 10 років!

4. Приклад використання діалогового вікна:

import javax.swing.*;
class MyOptionPane{
public static void main(String args[]){
String name;
int age;

System.out.println("Як Вас звати?");
name=JOptionPane.showInputDialog(
"Вкажіть Ваше ім'я");
System.out.println(
"Доброго дня, "+name+"!");
System.out.println(
"Скільки Вам років?");
age=Integer.parseInt(JOptionPane.showInputDialog(
"Вкажіть Ваш вік"));
System.out.println(name+
", Вам "+age+" років!"); 
System.exit(0);
}
}


Результат:


Як Вас звати?
Доброго дня, Оля!
Скільки Вам років?
Оля, Вам 10 років!

5. Приклад роботи з файлами:

Є два файли, необхідно скопіювати один файл у інший. Для цього ми створюємо два байтові потоки: вхідний потік, через який читатиметься наш файл first.txt і створюємо інший вихідний (output) потік, який записуватиме прочитані дані у second.txt. Для цього будемо використовувати два класи FileInputStream та FileOutputStream.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

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

//створюємо об'єктні змінні, які посилатимуться на наші потоки
FileInputStream in = null;
FileOutputStream out = null;

// При помилках читання/запису можуть генеруватися винятки, тож потрібно перехопити їх
// Наприклад, помилка може виникнути, при відсутності файлу
first.txt у вказаному місці
try {

// створюємо вхідний і вихідний потік
// файл first.txt повинен вже існувати
// якщо second.txt не буде існувати,
// то буде створений при спробі запису

in = new FileInputStream("C:/Users/HOME/workspace/inputOutput/src/inputOutput/first");
out = new FileOutputStream("C:/Users/HOME/workspace/inputOutput/src/inputOutput/second.txt");
int c;

//Допоки з файлу first.txt не буде прочинато всі байти,
//читаємо байти з файлу first.txt і записуємо даний байт у second.txt

//якщо потік не повертає -1(не досягнено кінець файлу),
//то копіюємо наступний байт

while ((c = in.read()) != -1) {
out.write(c);
}
} finally { //дії коли не знайдено файли
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}

6. Приклад зчитування з файлу:

import java.io.*;
import javax.swing.*;
class FindFellow{
public static void main(String args[]) throws IOException{
String fileName;
String name;
String s;
fileName=JOptionPane.showInputDialog(
"Вкажіть ім'я файлу:");
try{
FileInputStream fin=new FileInputStream(
"C:/Users/HOME/workspace/inputOutput/src/inputOutput/"+fileName);
BufferedReader br=new BufferedReader(new InputStreamReader(fin));
name=JOptionPane.showInputDialog(
"Вкажіть прізвище співробітника:");
while(true){
s=br.readLine();
try{
if(s.equalsIgnoreCase(name)){
System.out.println(
"Прізвище : "+name);
System.out.println(
"Ім'я : "+br.readLine());
System.out.println(
"По-батькові: "+br.readLine());
System.out.println(
"Вік : "+br.readLine());
System.out.println(
"Тел. : "+br.readLine());
break;}
}catch(NullPointerException e){
System.out.println(
"Такого співробітника немає!");
break;}}
fin.close();
}catch(FileNotFoundException e){
System.out.println(
"Помилка доступу до файлу: "+e);}
System.exit(0);
}
}


.