Таблица 10.1. Классы байтовых потоковКласс байтового потокаОписаниеBufferedlnputStreamБуферизованный поток вводаBufferedOutputStreamБуферизованный поток выводаByteArrayInputStreamПоток ввода для чтения из байтового массиваByteArrayOutputStreamПоток вывода для записи в байтовый массивDatalnputStreamПоток ввода с методами для чтения стандартных типов данных JavaDataOutputStreamПоток вывода с методами для записи стандартных типов данных JavaFileInputStreamПоток ввода для чтения из файлаFileOutputStreamПоток вывода для записи в файлFilterlnputStreamПодкласс, производный от класса InputStreamFilterOutputStreamПодкласс, производный от класса OutputStreamInputStreamАбстрактный класс, описывающий потоковый вводObjectInputStreamПоток для ввода объектовObjectOutputStreamПоток для вывода объектовOutputStreamАбстрактный класс, описывающий потоковый выводPipedlnputStreamПоток конвейерного вводаPipedOutputStreamПоток конвейерного выводаPrintStreamПоток вывода с методами print () и println ()PushbacklnputStreamПоток ввода с возвратом прочитанных байтов в потокRandomAccessFileКласс, поддерживающий файловый ввод-вывод с произвольным доступомSequenceInputStreamПоток ввода, сочетающий в себе несколько потоков ввода для поочередного чтения данных из нихКлассы символьных потоков
Для определения символьных потоков служат две иерархические структуры классов, на вершине которых находятся абстрактные классы Reader и Writer соответственно. Класс Reader и его подклассы используются для чтения, а класс Writer и его подклассы — для записи данных. Конкретные классы, производные от классов Reader и Writer, оперируют символами в уникоде.
Классы, производные от классов Reader и Writer, предназначены для выполнения различных операций ввода-вывода символов. Символьные классы присутствуют в Java параллельно с байтовыми классами. Классы символьных потоков приведены в табл. 10.2.Таблица 10.2. Классы символьных потоковКласс символьного потокаОписаниеBufferedReaderБуферизованный поток ввода символовBufferedWriterБуферизованный поток вывода символовCharArrayReaderПоток ввода для чтения из символьного массиваCharArrayWriterПоток вывода для записи в символьный массивFileReaderПоток ввода для чтения символов из файлаFileWriterПоток вывода для записи символов в файлFilterReaderКласс для чтения символов с фильтрациейFilterWriterКласс для записи символов с фильтрациейInputStreamReaderПоток ввода с преобразованием байтов в символыLineNumberReaderПоток ввода с подсчетом символьных строкOutputStreamWriterПоток вывода с преобразованием символов в байтыPipedReaderПоток конвейерного вводаPipedWriterПоток конвейерного выводаPrintWriterПоток вывода с методами print () и println ()PushbackReaderПоток ввода с возвратом прочитанных символов в потокReaderАбстрактный класс, описывающий потоковый ввод символовStringReaderПоток ввода для чтения из символьной строкиStringWriterПоток вывода для записи в символьную строкуWriterАбстрактный класс, описывающий потоковый вывод символовВстроенные потоки
Как вам должно быть уже известно, во все программы на Java автоматически импортируется пакет java. lang. В этом пакете определен класс System, инкапсулирующий некоторые элементы среды выполнения программ. Помимо прочего, в нем содержатся предопределенные переменные in, out и err, представляющие стандартные потоки ввода-вывода. Эти поля объявлены как public, final и static. А это означает, что ими можно пользоваться в любой другой части программы, не ссылаясь на конкретный объект типа System.
Переменная System.out ссылается на поток стандартного вывода. По умолчанию этот поток связан с консолью. А переменная System, in ссылается на поток стандартного ввода (по умолчанию с клавиатуры). И наконец, переменная System.err ссылается на поток стандартных сообщений об ошибках, которые по умолчанию выводятся на консоль. По мере необходимости все эти потоки могут быть перенаправлены на другие совместимые устройства ввода-вывода.
Поток System.in представляет собой объект типа InputStream, а потоки System.out и System.err — объекты типа PrintStream. Хотя эти потоки обычно используются для чтения и записи символов, они на самом деле являются байтовыми потоками. Дело в том, что эти потоки были определены в первоначальной спецификации Java, где символьные потоки вообще не были предусмотрены. Как станет ясно в дальнейшем, для этих потоков можно по необходимости создать оболочки, превратив их в символьные потоки.Применение байтовых потоков
Начнем рассмотрение системы ввода-вывода в Java с байтовых потоков. Как пояснялось ранее, на вершине иерархии байтовых потоков находятся классы InputStream и OutputStream. Методы из класса InputStream приведены в табл. 10.3, а методы из класса OutputStream — в табл. 10.4. При возникновении ошибок в процессе выполнения методы из классов InputStream и OutputStream могут генерировать исключения типа IOException. Методы, определенные в этих двух абстрактных классах, доступны во всех подклассах. Таким образом, они формируют минимальный набор функций ввода-вывода, общих для всех байтовых потоков.
Таблица 10.3. Методы, определенные в классе InputStreamМетодОписаниеint available()Возвращает количество байтов, доступных для чтенияvoid close ()Закрывает поток ввода. При последующей попытке чтения из потока генерируется исключение IOExceptionvoid mark(int numBytes)Ставит отметку на текущей позиции в потоке. Отметка доступна до тех пор, пока на будет прочитано количество байтов, определяемое параметром numBytesboolean markSupported()Возвращает логическое значение true, если методы mark() и reset () поддерживаются в вызывающем потокеint read()Возвращает целочисленное представление следующего байта в потоке. Если достигнут конец потока, возвращается значение -1int read(byte buffer[])Предпринимает попытку прочитать количество байтов, определяемое выражением buffer, length, в массив buffer и возвращает фактическое количество успешно прочитанных байтов. Если достигнут конец потока, возвращается значение -1int read(byte buffer[], int offset, int numBytes)Предпринимает попытку прочитать количество байтов, определяемое параметром numBytes, в массив buffer, начиная с элемента buffer[offset]. Если достигнут конец потока, возвращается значение -1void reset()Устанавливает указатель ввода на помеченной ранее позицииlong skip (long numBytes)Пропускает количество байтов, определяемое параметром numBytes, в потоке ввода. Возвращает фактическое количество пропущенных байтов
Таблица 10.4. Методы, определенные в классе OutputStreamМетодОписаниеvoid close()Закрывает выходной поток. При последующей попытке записи в поток генерируется исключение IOExceptionВыводит содержимое выходного буфера вывода вvoid flush()Выводит содержимое выходного буфера вывода в целевой поток. По завершении этой операции выходной буфер очищаетсяvoid write(int b)Записывает один байт в поток вывода. Параметр b относится к типу int, что позволяет вызывать данный метод в выражениях, не приводя результат их вычисления к типу bytevoid write(byte buffer[])Записывает массив в поток выводаvoid write(byte buffer[], int offset, int numBytes)Записывает в поток вывода часть массива buffer длиной numBytes байтов, начиная с элемента buffer[offset]Консольный ввод
Первоначально единственный способ реализовать консольный ввод в Java состоял в использовании байтовых потоков, и во многих программах на Java до сих пор используются исключительно потоки данного типа. В настоящее время для разработки прикладных программ доступны как байтовые, так и символьные потоки. В коммерческих приложениях для чтения данных с консоли в основном используются символьные потоки. Такой подход упрощает локализацию программ и их сопровождение. Ведь намного удобнее оперировать непосредственно символами и не тратить время и труд на преобразование символов в байты, а байтов — в символы. Но в простых служебных и прикладных программах, где данные, введенные с клавиатуры, обрабатываются непосредственно, удобно пользоваться байтовыми потоками. Именно поэтому они здесь и рассматриваются.