У мові програмування Java введення/виведення інформації побудовано на понятті потоку.
Потік — це абстрактне поняття для позначення джерела чи приймача даних, що може передавати або отримувати дані.
Для використання класу потоку введення/виведення потрібно імпортувати пакет java.io:
import java.io.*;
У мові Java розрізняють два види потоків:
Байтові потоки введення/виведення поділяють на нащадків таких класів:
InputStream — абстрактний клас, що описує байтовий потік введення.
Нащадки InputStreamОсновні методи класу InputStream:
Основні методи класу OutputStream:
Символьні потоки введення/виведення поділяють на нащадків таких класів:
Reader — абстрактний клас, що описує потік введення символів.
Нащадки Reader:Основні методи класу Reader:
Основні методи класу Writer:
f.append(c) — додає в кінець вихідного потоку символ c (тип char), повертає об'єкт Writer;
Стандартні потоки введення/виведення втілені у пакунку java.lang. Цей пакунок імпортується автоматично, тобто не обов’язково використовувати вказівку import. Базовим класом цього пакунку є клас System з трьома змінними, які є посиланнями на стандартні (наперед визначені) потоки введення/виведення:
— див. приклад коду:
package work;
import java.io.*;
import java.util.Scanner;
public class Work
{ public static void main(String[] args) throws IOException
{ Scanner s = new Scanner(System.in);
InputStream i = System.in;
PrintStream o = System.out;
PrintStream e = System.err;
o.println("Введіть літеру латиниці, цифру або знак пунктуації");
int code = i.read();
o.println("Код введеного символа "+code);
o.println("Введіть ціле число ");
int n = s.nextInt();
o.println("Було введено число "+n);
e.println("Жодних проблем!");
char a[] = new char[5];
InputStreamReader isr = new InputStreamReader(System.in);
o.println("Введіть символи (до 5):");
n = isr.read(a, 1, 4);
o.println("Кількість введених символів разом з ознакою кінця рядка: " + n);
for (int j=0; j<a.length; j++)
o.println("a[" + j + "] = " + a[j]);
}
}з таким результатом виконання у консолі:
Введіть літеру латиниці, цифру або знак пункткації * Код введеного символа 42 Введіть ціле число 22 Було введено число 22 Жодних проблем! Введіть символи (до 5): qw Кількість введених символів: 3 a[0] = a[1] = q a[2] = w a[3] = a[4] =
Клас Scanner використовують для аналізу і введення даних потоку введення.
Наприклад, для введення цілого числа (не символа, не рядка), як це зроблено у поданому вище прикладі коду.
Методи класу Scanner
| Тип результату повертання | Назва методу і тип аргумента (в дужках) | Призначення (що робить?) |
|---|---|---|
| void | close() | Закриває об'єкт сканера |
| Pattern | delimiter() | Повертає шаблон, який об'єкт Scanner в даний час використовує для порівняння роздільників. |
| String | findInLine (Pattern) | Повертає об'єкт String, який задовольняє вказаному шаблону. |
| String | findInLine (String) | Шукає наступне входження шаблону, створеного з указаного рядка, при незтуванні роздільників. |
| String | findWithinHorizon (Pattern, int) | Шукає наступне входження вказаного шаблону. |
| String | findWithinHorizon (String, int) | Шукає наступне входження шаблону введення, ігноруючи роздільник |
| boolean | hasNext() | Повертає true, якщо у цього сканера є дані на вході, інакше повертає false. |
| boolean | hasNext(Pattern) | Повертає true, якщо наступні повні дані відповідають вказаному шаблону, інакше повертає false. |
| boolean | hasNext(String) | Повертає true, якщо наступні дані відповідають шаблону, створеному з вказаного рядка, інакше повертає false. |
| boolean | hasNextBigDecimal() | Повертає true, якщо наступні дані можна тлумачити як BigDecimal за допомогою методу nextBigDecimal, інакше повертає false. |
| boolean | hasNextBigInteger() | Повертає true, якщо наступні дані можна тлумачити як BigInteger за допомогою методу nextBigInteger, інакше повертає false. |
| boolean | hasNextBigInteger(int) | Аналог попереднього методу для вказаної основи. |
| boolean | hasNextBoolean() | Повертає true, якщо наступні дані потоку мають логічний тип, інакше повертає false. |
| boolean | hasNextByte() | Повертає значення true, якщо наступний байт можна перетворити у тип даних байта, інакше повертає false. |
| boolean | hasNextByte(int) | Аналог попереднього методу для вказаної основи. |
| boolean | hasNextDouble() | Повертає значення true, якщо наступні дані на вході можна тлумачити як значення типу Double за допомогою методу nextDouble, інакше повертає false. |
| boolean | hasNextFloat() | Повертає значення true, якщо наступні дані на вході можна тлумачити як значення типу float за допомогою методу nextFloat, інакше повертає false. |
| boolean | hasNextInt() | Повертає значення true, якщо наступні дані на вході можна тлумачити як значення типу int за допомогою методу nextInt, інакше повертає false. |
| boolean | hasNextInt(int) | Аналог попереднього методу при вказаній основі числення. |
| boolean | hasNextLine() | Повертає логічний тип даних, який відповідає новому рядку String, яку містить об'єкт Scanner. |
| boolean | hasNextLong() | Повертає true, якщо наступні дані на вході сканера можна тлумачити як значення типу long з використанням методу nextLong, інакше повертає false. |
| boolean | hasNextLong(int) | Аналог попереднього методу при вказаній основі числення. |
| boolean | hasNextShort() | Повертає true, якщо наступні дані на вході сканера можна тлумачити як значення типу Short з використанням методу nextShort, інакше повертає false. |
| boolean | hasNextShort(int) | Аналог попереднього методу при вказаній основі числення. |
| IOException | ioException() | Повертає IOException, останній раз виданий в основі сканера Readable. |
| Locale | locale() | Повертає локаль. |
| MatchResult | match() | Повертає результат останньої дії з об'єктом. |
| String | next() | Сканує і повертає наступну повну частину даних. |
| String | next (Pattern) | Сканує і повертає наступну повну частину даних, якщо вона відповідає вказаному шаблону. |
| String | next (String) | Сканує і повертає наступну повну частину даних, якщо вона відповідає вказаному шаблону, створеному із зазначеного рядка. |
| BigDecimal | nextBigDecimal() | Сканує і повертає наступну повну частину даних як BigDecimal. |
| BigInteger | nextBigInteger() | Сканує і повертає наступну повну частину даних як BigInteger. |
| BigInteger | nextBigInteger(int) | Аналог попереднього методу при вказаній основі числення. |
| boolean | nextBoolean() | Сканує і повертає наступну частину даних як логічне значення. |
| byte | nextByte() | Сканує і повертає наступну частину даних як тип byte. |
| byte | nextByte(int) | Аналог попереднього методу при вказаній основі числення. |
| double | nextDouble() | Сканує і повертає наступну частину даних як тип double. |
| float | nextFloat() | Сканує і повертає наступну частину даних як тип float. |
| int | nextInt() | Сканує і повертає наступну частину даних як тип int. |
| int | nextInt(int) | Аналог попереднього методу при вказаній основі числення. |
| String | nextLine() | Переміщує сканер за поточний рядок і повертає пройдені дані. |
| long | nextLong() | Сканує і повертає наступну частину даних як тип long. |
| long | nextLong(int) | Аналог попереднього методу при вказаній основі числення. |
| short | nextShort() | Сканує і повертає наступну частину даних як тип short. |
| short | nextShort(int) | Аналог попереднього методу при вказаній основі числення. |
| int | radix() | Повертає поточну основу числення. |
| void | remove() | Вилучає поточний об'єкт. |
| Scanner | reset () | Скидає налаштування локалі, радіуса і роздільника. |
| Scanner | skip (Pattern) | Пропускає введення, що відповідає вказаному шаблону, нехтуючи роздільниками. |
| Scanner | skip (String) | Пропускає введення, що відповідає шаблону, створеному із зазначеного рядка. |
| String | toString() | Повертає рядкове подання. |
| Scanner | useDelimiter (Pattern) | Встановлює шаблон обмеження поточного сканера за вказаним шаблоном. |
| Scanner | useDelimiter (String) | Аналог попереднього методу, але за шаблоном, створеним ызз зазначеного рядка. |
| Scanner | useLocale (Locale) | Встановлює вказану локалізацію. |
| Scanner | useRadix (int) | Встановлює вказану основу системи числення (radix). |
Зчитування символів з консолі з буферизацією здійснюють, розташувавши представника класу InputStreamReader в оболонку об’єкту класу BufferedReader. Загальна форма конструктора класу BufferedReader така:
BufferedReader(i);
Тут i — потік даних (файл, консоль тощо), тип Reader. У випадку консолі задають представника класу InputStreamReader. Такий підхід реалізує паттерн Декоратор (Decorator). У паттерні Декоратор екземпляр одного класу служить оболонкою для екземпляру іншого класу. Таким чином відбувається нашаровування об’єктів — див. приклад зчитування символів з консолі з буферизацією.
package work;
import java.io.*;
public class Work
{ public static void main(String[] args) throws IOException
{ PrintStream o = System.out;
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
char c;
o.println("Введіть символи, '/' - для виходу.");
do { c = (char) br.read();
o.println(c);
}
while (c != '/');
}
}з таким можливим виглядом консолі.
Введіть символи, '/' - для виходу. qw q w e/ e /
Введення з консолі й розбиття рядків проілюструємо таким прикладом:
package work;
import java.io.*;
import java.util.Scanner;
public class Work
{ public static void main(String[] args) throws IOException
{ Scanner in = new Scanner(System.in);
System.out.print("Введіть рядок тексту: слова, розділені пробілом.\n");
String s = in.nextLine();
String[] t = s.split(" "); // розбиття за роздільником " " - пробілом
System.out.println("Введений рядок містить "+t.length+" слів.");
for (int j=0; j<t.length; j++) {System.out.println(t[j]);}
}
}
Метод split класу String має два аргументи:обов'язковий — рядок регулярного виразу, за яким здійснюють розбиття. Якщо використовують кілька роздільників, їх записують через вертикальну риску |.
необов'язковий — кількість слів (тип int), рахуючи від початку рядка. Якщо не вказано або вказано від'ємне значення, буде виділено всі всі слова.
Клас File містить кілька конструкторів файлових об'єктів, кожен з яких дозволяє формувати назву файлу (у тому числі теки) різними способами. Найуживанішим є конструктор, що отримує один рядок типу String, уякому записано повну (абсолютну) або скорочену (відносну) назву файлу, який пов'язують з файловим об'єктом. Також є конструктори, що формують назву файлу з кількох частин — див. приклад з використанням методу getPath, описаного нижче.
package work;
import java.io.File;
public class Work
{ public static void main(String[] args)
{ File f1 = new File("output.txt");
System.out.println(f1.getPath());
File f2 = new File("/home", "/chief");
System.out.println(f2.getPath());
File f3 = new File(f2,"output.txt");
System.out.println(f3.getPath());
}
}Результат виконання програми такий:
output.txt /home/chief /home/chief/output.txt
Основні методи класу File
f.getName() — повертає рядок — назву файлу файлового об'єкта f;
f.getPath() — повертає рядок — адресу файлового об'єкта f, задану при його створенні (назва з розширенням або повний шлях);
f.isAbsolute() — повертає truе або false — результат визначення, чи було вказано повний шлях до файлу при створенні файлового об'єкта f;
f.getAbsolutePath() — повертає рядок — повний шлях до файлу, пов'заного з файловим об'єктом f;
f.canRead() — повертає truе або false — результат визначення того, чи допускає файловий об’єкт f читання;
f.canWrite() — повертає truе або false — результат визначення того, чи допускає файловий об’єкт f запис;
f.exists() — повертає truе або false — результат визначення наявності файлу (каталогу);
f.isDirectory() — повертає truе або false — результат визначення того, чи зв’язаний файловий об’єкт а є текою (директорією, каталогом);
f.isFile() — повертає truе або false — результат визначення того, чи зв’язаний файловий об’єкт f є файлом, що не є текою;
f.isHidden() — повертає truе або false — результат визначення того, чи файловий об’єкт f є прихованим;
f.length() — повертає ціле число типу long — розмір у байтах файлу, зв’язаного з файловим об’єктом f;
f.delete() — видаляє файл, зв’язаний з файловим об’єктом f. Повертає truе при успішному видаленні, інакше повертає false;
f.mkdir() — створює теку (директорію, каталог), зв’язану з файловим об’єктом f. Повертає truе при успішному створенні, інакше повертає false;
f.mkdirs() — створює послідовність вкладених тек (директорій, каталогів), якщо при створенні файлового об’єкту f в аргументі конструктора File записано послідовність вкладених тек, розділених
подвійними зворотніми похилими рисками (подвійними — з метою екранування службового символу). Як, наприклад, у такій вказівці:
File f = new File("C:\\a\\b\\c");
Повертає truе при успішному створенні, інакше повертає false;
f.renameTo(g) — змінює назву файлу, зв’язаного з файловим об’єктом f, на ту, що зв'язана з файловим об’єктом g. Повертає truе при успішній зміні назві, інакше повертає false;
f.getTotalSpace() — повертає ціле число типу long — розмір у байтах диску, зв'язаного з файловою змінною f;
f.getFreeSpace() — повертає ціле число типу long — розмір у байтах вільного місця на диску, зв'язаного з файловою змінною f. Якщо при конструюванні файлової змінної вказано не лиск, а назву файлу, то визначають об’єм вільного місця для носія, на якому цей файл розташовано;
f.getUsableSpace() — повертає ціле число типу long — розмір у байтах корисного вільного місця на диску, зв'язаного з файловою змінною f. Якщо при конструюванні файлової змінної вказано не диск, а назву файлу, то визначають об’єм вільного місця для носія, на якому цей файл розташовано.
Клас FileOutputStream призначено для запису байтів у файл. Він є похідним від класу OutputStream, тому успадковує всю його функціональність. Конструктор FileOutputStream має один два аргументи:
Якщо вказаного файлу немає, то його буде автоматично створено. Для записку рядка його потрібно спочатку перетворити у масив байтів — див. приклад запису рядка у файл.
package work;
import java.io. *;
public class Work
{ public static void main (String [] args)
{ String s = "Текст для запису"; // рядок для запису
try (FileOutputStream fout = new FileOutputStream ("output.txt"))
{ byte [] b = s.getBytes(); // перетворення рядка у масив байтів
fout.write (b, 0, b.length);
}
catch (IOException ex) {System.out.println(ex.getMessage());}
System.out.println ("Файл успішно записано");
}
}
Для автоматичного закриття файлу і звільнення ресурсу об'єкт FileOutputStream створюють за допомогою вказівки вигляду try … catch. При потребі записати лише один (перший) байт використовують перевантаження методу write:
fout.write(b[0]);
Клас FileInputStream призначено для зчитування даних з файлу. Він є спадкоємцем класу InputStream і реалізує всі його методи. Для створення об'єкта FileInputStream використовують декілька конструкторів. Найчастіше використовуваний як параметр використовує рядок s — шлях до зчитувати файлу:
FileInputStream (s) throws FileNotFoundException
Якщо файл не можливо відкрити (наприклад, за вказаним шляхом такого файлу немає), то буде породжено виключення FileNotFoundException.
Розглянемо приклад виведення у консоль даних з раніше створеного файлу.
package work;
import java.io. *;
public class Work
{ public static void main (String [] args)
{ try (FileInputStream fin = new FileInputStream ("input.txt"))
{ System.out.printf ( "Розмір файлу: %d байт \n",fin.available());
int i = -1;
while ( (i = fin.read()) != -1) {System.out.print ((char) i);}
}
catch (IOException ex) {System.out.println (ex.getMessage());}
}
}
У розглянутому прикладі байти зчитють у змінну i доти, поки поток непорожній, тобто поки метод read число, відмінне від -1. Потім кожний зчитаний байт перетворюють в об'єкт типу char і виводять у консоль. Якщо текст містить літери кирилиці, можливе неправильне відображення вмісту файлу в консолі.
Перевірку умови fin.read()) != -1 можна замінити на перевірку справдження виразу fin.ready().
Переписати вміст одного файлу в інший можна таким чином.
package work;
import java.io. *;
public class Work
{ public static void main (String [] args)
{ try (FileInputStream fin = new FileInputStream ("input.txt");
FileOutputStream fout = new FileOutputStream("output.txt")
)
{ byte [] b = new byte [fin.available()];
fin.read (b, 0, b.length);
fout.write(b, 0, b.length);
}
catch (IOException ex) {System.out.println(ex.getMessage());}
}
}Клас FileWriter. Зазвичай використовують конструктор класу з такими двома аргументами:
Є що конструктор з одним аргументом типу FileDescriptor.
Якщо вказаного файлу немає, то його буде створено автоматично.
Наступний приклад ілюструє переписування вмісту файлу input.txt у файл output.txt
package work;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Work
{ public static void main(String[] args)
{ try
{ FileReader in = new FileReader( "input.txt");
FileWriter out= new FileWriter("output.txt");
BufferedReader bin = new BufferedReader(in);
String s = bin.readLine();
while (s != null)
{ out.write(s+"\n");
System.out.println(s);
s = bin.readLine();
}
out.close();
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
}
}
Текст упорядкував Олександр Рудик.