Потоки в Java

Java-программы выполняют ввод/вывод через потоки. Поток является абстракцией, которая или производит, или потребляет информацию. Поток связывается с физическим устройством с помощью системы ввода/вывода Java (Java I/O system). Все потоки ведут себя одинаковым образом, хотя фактические физические устройства, с которыми они связаны, могут сильно различаться. Таким образом, одни и те же классы и методы ввода/вывода можно применять к устройствам любого типа. Это означает, что поток ввода может извлекать много различных видов входных данных: из дискового файла, с клавиатуры или сетевого разъема. Аналогично, поток вывода может обратиться к консоли, дисковому файлу или сетевому соединению (сокету).
Благодаря потокам, ваша программа выполняет ввод/вывод, не понимая различий между клавиатурой и сетью. Java реализует потоки с помощью иерархии классов, определенных в пакете java.io.

Байтовые и символьные потоки
Java 2 определяет два типа потоков: байтовый и символьный. Байтовые потоки предоставляют удобные средства для обработки ввода и вывода байт. Байтовые потоки используются, например, при чтении или записи данных в двоичном коде. Символьные потоки предоставляют удобные средства для обработки ввода и вывода символов. Они используют Unicode и поэтому могут быть. Кроме того, в некоторых случаях символьные потоки более эффективны, чем байтовые. Первоначальная версия Java (Java 1.0) не включала символьные потоки, и таким образом, весь ввод/вывод был байтовым. Символьные потоки были добавлены в Java 1.1, а некоторые байтовые классы и методы были исключены.

Классы байтовых потоков
Байтовые потоки определяются в двух иерархиях классов. Наверху этой иерархии — два абстрактных класса: InputStream и OutputStream. Каждый из этих абстрактных классов имеет несколько конкретных подклассов , которые обрабатывают различия между разными устройствами, такими, как дисковые файлы, сетевые соединения и даже буферы памяти.
Абстрактные классы InputStream и OutputStream определяют несколько ключевых методов, которые реализуются другими поточными классами. Два наиболее важных— read() и write(), которые соответственно читают и записывают байты данных. Оба метода объявлены как абстрактные внутри
классов InputStream и OutputStream и переопределяются производными поточными классами.

Поточный класс Назначение
InputStream
OutputStream
Абстрактные классы, которые описывают поточный ввод и вывод
BufferedInputStream
BufferedOutputStream
Буферизированный поток ввода и вывода
ByteArrayOutputStream Поток ввода, который читает из байт-массива
Поток вывода, который записывает в байт-массив
FileInputStream
FileOutputStream
Поток ввода, который читает из файла
Поток вывода, который записывает в файл
RandomAccessFile Поддерживает ввод/вывод файла произвольного доступа

 

Классы символьных потоков
Символьные потоки определены в двух иерархиях классов. Наверху этой иерархии два абстрактных класса: Reader и Writer. Они обрабатывают потоки символов Unicode. В Java существуют несколько конкретных подклассов каждого из них. Классы Reader и Writer – наследники InputStream и OutputStream. Если с их помощью записывать или считывать текст, то сначала необходимо сопоставить каждому символу его числовой код. Такое соответствие называется кодировкой. Классы символьных потоков показаны в таблице.
Абстрактные классы Reader и Writer определяют несколько ключевых методов, которые реализуются другими поточными классами. Два самых важных метода — read() и write(), которые читают и записывают символы данных, соответственно. Они переопределяются производными поточными классами.

Символьный класс Назначение
Reader
Writer
Абстрактные классы символьного потока ввода и вывода
BufferedReader
BufferedWriter
Буферизированные символьные потоки ввода и вывода
FileReader
FileWriter
Поток ввода, который читает поток символов из файла;
Выходной поток, который записывает символы в файл
StringReader
StringWriter
Поток ввода, который читает из строки;
Поток вывода, который записывает в строку
PrintWriter Поток вывода, который поддерживает методы print() и println()

 

Известно, что Java использует кодировку Unicode, в которой символы представляются двухбайтным кодом. Байтовые потоки зачастую работают с текстом упрощенно – они просто отбрасывают старший байт каждого символа. В реальных же приложениях они могут использовать различные кодировки (даже для русского языка их существует несколько). Поэтому в версии Java 1.1 появился дополнительный набор классов, основывающийся на типах Reader и Writer.
Эта иерархия очень схожа с аналогичной для байтовых потоков InputStream и OutputStream. Главное отличие между ними – Reader и Writer работают с потоком символов (char). Только чтение массива символов в Reader описывается методом read(char[]), а запись в Writerwrite(char[]).
В таблице приведены соответствия классов для байтовых и символьных потоков.

 

Байтовый поток Символьный поток
InputStream Reader
OutputStream Writer
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
Нет аналога InputStreamReader
Нет аналога OutputStreamWriter
FileInputStream FileReader
FileOutputStream FileWriter
FilterInputStream FilterReader
FilterOutputStream FilterWriter
BufferedInputStream BufferedReader
BufferedOutputStream BufferedWriter
PrintStream PrintWriter
DataInputStream Нет аналога
DataOutputStrea Нет аналога
ObjectInputStream Нет аналога
ObjectOutputStream Нет аналога
PipedInputStream PipedReader
PipedOutputStream PipedWriter
StringBufferInputStream StringReader
Нет аналога StringWriter
LineNumberInputStream LineNumberReader
PushBackInputStream PushBackReader
SequenceInputStream Нет аналога

 

Как видно из таблицы, различия крайне незначительны и предсказуемы.
Например, конечно же, отсутствует преобразование в символьное представление примитивных типов Java и объектов (DataInput/Output, ObjectInput/Output). Добавлены классы-мосты, преобразующие символьные потоки в байтовые: InputStreamReader и OutputStreamWriter. Именно на их основе реализованы FileReader и FileWriter. Метод available() класса InputStream в классе Reader отсутствует, он заменен методом ready(), возвращающим булевое значение, – готов ли поток к считыванию (то есть будет ли считывание произведено без блокирования).
В остальном же использование символьных потоков идентично работе с байтовыми потоками.
Классы-мосты InputStreamReader и OutputStreamWriter при преобразовании символов также используют некоторую кодировку. Ее можно задать, передав в конструктор в качестве аргумента ее название. Если оно не будет соответствовать никакой из известных кодировок, будет брошено исключение UnsupportedEncodingException. Вот некоторые из корректных значений этого аргумента (чувствительного к регистру!) для распространенных кодировок: "Cp1251", "UTF-8", "8859_1" и т.д.
В следуюшем примере приведена программа, которая демонстрирует read(), читая символы с консоли, пока пользователь не напечатает «q»:

import java.io.*;
class BRRead {
public static void main(String args [ ]) throws IOException
{
char c;
BufferedReader br = new
BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter symbols or 'q' to exit");
// чтение символов
do {
c= (char)br.read();
System.out.println(c);
}
while(c != 'q');
}
}

Результат выполнения программы:

Enter symbols or 'q' to exit
123abcq
1
2
3
а
b
с
q

Следующая   программа   демонстрирует   BufferedReader   и   метод readLine(). Она читает и отображает строки текста, пока не будет введено слово «stop».

import java.io.*;
class BRReadLines {
public static void main(String args[])throws IOException
{
// создать BufferedReader, используя System.in
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String str;
System.out.println("Enter text");
System.out.println("Enter 'stop' to exit");
do {
str = br.readLine();
System.out.println(str);
} while(!str.equals("stop"));
}
}

 

Добавить комментарий


Защитный код
Обновить

Разработчику

Скрипты