InputStreamReader и OutputStreamWriter
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Эти классы обеспечивают возможность преобразования байтовых потоков ввода в символьные потоки чтения и символьных потоков записи в байтовые потоки вывода соответственно, с учётом заданной кодировки символов или кодировки, принятой по умолчанию в конкретной локальной системе. Объекту InputStreamReader в качестве источника передаётся байтовый поток ввода, и InputStreamReader обеспечивает чтение соответствующих символов Unicode. Объекту OutputStreamWriter в качестве получателя передаётся байтовый поток вывода, и OutputStreamWriter сохраняет в нём байтовые представления символов Unicode.

Описания конструкторов классов приведены ниже:

· public InputStreamReader(InputStream in)
Создаёт объект InputStreamReader для ввода данных из указанного потока InputStream с учётом кодировки символов, принятой по умолчанию.

· public InputStreamReader(InputStream in, String encoding) throws UnsupportedEncodingException
Создаёт объект InputStreamReader для ввода данных из указанного потока InputStream с учётом заданной кодировки символов encoding. Если кодировка encoding не поддерживается, выбрасывается исключение типа UnsupportedEncodingException.

· public OutputStreamWriter (OutputStream out)
Создаёт объект OutputStreamWriter для вывода данных в указанный поток OutputStream с учётом кодировки символов, принятой по умолчанию.

· public OutputStreamWriter (OutputStream out, String encoding) throws UnsupportedEncodingException
Создаёт объект OutputStreamWriter для вывода данных в указанный поток OutputStream с учётом заданной кодировки символов encoding. Если кодировка encoding не поддерживается, выбрасывается исключение типа UnsupportedEncodingException.

Методы read класса InputStreamReader обеспечивают ввод байтов из заданного потока InputStream и преобразование их в символы с использованием соответствующей кодировки. Аналогично, методы write класса OutputStreamWriter получают переданные символы, преобразуют их в байты, используя соответствующую кодировку, и выводят в заданный поток OutputStream.

В обоих классах при закрытии потока-преобразователя также закрывается и связанный с ним байтовый поток. Такое поведение не всегда желательно (например, при преобразовании данных из стандартных потоков), поэтому вопрос, когда именно следует закрывать поток InputStreamReader или OutputStreamWriter заслуживает особого внимания.

В обоих классах поддерживается метод getEncoding, возвращающий строку с каноническим наименованием кодировки, используемой потоком, либо значение null, если поток уже закрыт.

Классы FileReader и FileWriter являются расширенными версиями классов InputStreamReader и OutputStreamWriter соответственно и обеспечивают возможности обработки файловых данных с поддержкой Unicode и локальных стандартов кодировки символов.

Классов ReaderInputStream и WriterOutputStream, которые могли бы обеспечить трансляцию символьных потоков в байтовые и наоборот, не существует.





Краткий обзор классов потоков

В пакете java . io определён целый ряд типов потоков. Типы потоков обычно представлены парами классов, отвечающими за ввод (чтение) и вывод (запись) данных, и большинство из них реализовано как в байтовом, так и в символьном вариантах. Некоторые из потоков обладают свойствами, определяющими поведение остальных потоков.

Потоки Filter

Классы семейства фильтрованных потоков (filtered streams) Filter – FilterInputStream, FilterOutputStream, FilterReader и FilterWriter – позволяют объединять потоки в цепочки для получения составных потоков, обладающих расширенным набором функций. Каждый фильтрованный поток данных привязывается к другому потоку, которому передаёт полномочия по фактическому выполнению операций ввода или вывода.

Байтовые потоки Filter обладают дополнительными конструкторами, получающими в качестве параметров ссылки на объекты потоков данных соответствующего типа InputStream или OutputStream, которые обеспечивают ввод или вывод. Аналогично, в составе символьных потоков Filter предусмотрены конструкторы, которым передаются ссылки на объекты потоков Reader или Writer, выполняющих чтение или запись данных.

Позволяется связывать в единую цепочку любое количество байтовых (символьных) Filter-потоков ввода (чтения). Источником исходных данных может быть поток, не относящийся к семейству потоков Filter. Байтовый поток ввода нетрудно преобразовать в символьный поток чтения с помощью объекта класса InputStreamReader.

Подобным образом могут соединяться в цепочки и Filter-потоки вывода (записи), так что данные, выводимые (записываемые) в один поток, будут отфильтрованы и переданы следующему потоку. Все потоки вывода (записи) в цепочке, начиная с первого и заканчивая предпоследним, должны относиться к классу Filter, но последним может быть объект любого потокового класса вывода (записи). Для преобразования символьного потока записи в байтовый поток вывода можно воспользоваться объектом класса OutputStreamWriter.

Не все классы семейства Filter в действительности осуществляют изменение данных. Некоторые просто привносят дополнительные черты поведения, а другие предлагают новые интерфейсы взаимодействия с потоками (например, классы типа Print).

Потоки Buffered

Классы семейства буферизованных потоков (buffered streams) Buffered – BufferedInputStream, BufferedOutputStream, BufferedReader и BufferedWriter – осуществляют буферизацию данных, позволяющую избежать необходимости обращения к источнику (получателю) данных при выполнении каждой отдельной операции read или write. Эти классы часто используются в сочетании с потоками семейства File: доступ к данным на диске выполняется намного медленнее, чем к информации в буфере памяти, и средства буферизации помогают снизить потребность в обращениях к диску.

В каждом из потоков Buffered поддерживаются два конструктора: один в качестве параметра принимает ссылку на объект «внутреннего» потока и значение объёма буфера, а другому передаётся только ссылка на объект потока – размер буфера предлагается по умолчанию.

Когда метод read потока Buffered, вызываемый для ввода (чтения) данных, обнаруживает, что буфер потока пуст, он вызывает одноимённый метод потока источника, заполняет буфер настолько большой порцией данных, насколько это возможно (выполняя блокировку только в том случае, если необходимо дождаться появления данных), и возвращает запрошенные данные из буфера. При очередных обращениях к методу read объекта Buffered данные будут извлекаться из буфера, пока его содержимое не исчерпается, и в этот момент объекту вновь придётся вызвать read потока-источника. Процесс повторяется до тех пор, пока не иссякнет источник данных.

Buffered – потоки вывода (записи) ведут себя аналогичным образом. Когда write заполняет буфер данных, вызывается одноимённый метод потока-получателя, освобождающий буфер. Такой механизм буферизации помогает превратить последовательность запросов на вывод (запись) небольших порций данных, адресуемых объекту Buffered, в единственный вызов метода write потока-получателя.

Вот как можно построить байтовый буферизованный поток вывода данных в файл:

new BufferedOutputStream(new FileOutputStream(path));

Мы создаём объект класса FileOutputStream , передавая его конструктору аргумент строку, задающую путь к файлу, и на основе объекта FileOutputStream строим новый экземпляр класса BufferedOutputStream . Подобная схема позволяет осуществлять буферизацию байтовых данных, выводимых в файл.

Символьные потоки Buffered способны обращаться и со строками текста. Метод newLine класса BufferedWriter записывает в поток признак завершения строки. В каждой системе содержимое признака завершения строки, которое не обязательно должно ограничиваться единственным символом, задаётся по-разному; для этого используется одно из системных свойств типа String , line . separator . Обращаться к методу newLine для разграничения строк в текстовом файле следует, в частности, тогда, когда файл может быть открыт пользователем для визуального просмотра.

Метод readLine класса BufferedReader возвращает строку текста, считанную из потока, в виде объекта String. Метод способен распознавать разделители строк любого вида: перевод строки (\ n ), возврат каретки (\ r ) либо символ возврата каретки, сопровождаемый признаком перевода строки (\ r \ n ). При этом предполагается, что вы не пользовались средством line . separator для определения иного признака завершения строки. В противном случае корректность распознавания методом readLine строк, разграниченных посредством newLine , не гарантируется. В строку, возвращаемую методом readLine , разделитель не включается. Если в процессе считывания признак конца потока встречается раньше признака завершения строки, readLine возвращает значение null .

Потоки Piped

Канальные потоки (piped streams), определяемые классами семейства Piped - PipedInputStream, PipedOutputStream, PipedReader и PipedWriter – используются в виде пар ввода-вывода (записи-чтения). Данные, переданные в поток вывода (записи), служат источником для потока ввода (чтения). С каналом связан внутренний буфер, ёмкость которого определяется при реализации класса, что позволяет поддерживать разные уровни производительности процессов вывода и ввода; однако средств динамического управления размером буфера не существует.

Каналы реализуют механизм обмена данными между различными потоками вычислений. Единственный безопасный способ обращения с потоками данных Piped связан с использованием двух потоков вычислений: один из них осуществляет вывод данных, а другой – их ввод. Когда буфер канала полностью заполняется, попытка вывода данных в него приводит к блокированию соответствующего потока вычислений. Если операции вывода и ввода выполняются одним потоком вычислений, тот будет блокирован постоянно. Поток вычислений, осуществляющий ввод, блокируется, если буфер канала пуст.

Чтобы избежать опасности «вечного» блокирования одного потока вычислений, когда его «собрат» на другом конце канала прекращает работу, каждый канал отслеживает подлинность и работоспособность потоков вычислений, обращавшихся к нему с целью вывода и ввода данных последними. Канал, прежде чем блокировать текущий поток вычислений, проверяет, «жив» ли поток на другом конце канала. Если обнаруживается, что работа противоположного потока вычислений прекращена, текущий поток генерирует исключение типа IOException.

Потоки Piped должны быть связаны друг с другом. Это можно сделать, передав при создании потоков Piped конструктору потока PipedReader в качестве аргумента ссылку на поток PipedWriter. Порядок построения объектов пары Piped несущественен: наоборот, можно передать конструктору PipedWriter ссылку на объект PipedReader.

Потоки Piped должны быть соединены, но сделать это можно позже, после их создания, поскольку в составе классов Piped предлагаются и конструкторы без аргументов. Для соединения канальных потоков применяется метод connect. Методу PipedReader.connect в качестве параметра передаётся объект PipedWriter, а методу PipedWriter.connect – PipedReader. Как и при использовании конструкторов, не важно, присоединяется ли объект х к объекту у или наоборот, объект у к х, поскольку результат в обоих случаях одинаков. При попытках использования потоков Piped до их соединения или связывания ранее соединённых потоков выбрасывается исключение типа IOException.

Байтовые потоки ByteArray

Массивы байтов, размещённые в оперативной памяти, могут выступать в роли источника или получателя данных при работе с потоками семейства ByteArray.

Объект класса ByteArrayInputStream использует массив типа byte в качестве источника данных. В составе класса предусмотрены два конструктора:

· public ByteArrayInputStream(byte[] buf, int offset, int count)
Создаёт объект потока ByteArrayInputStream на основе части заданного массива байтов buf, начиная с элемента buf[offset] и заканчивая buf[offset+count-1] либо последним элементом массива, в зависимости от того, какой из двух будет достигнут раньше. Массив используется непосредственно (он не копируется), поэтому в процессе ввода данные изменять не следует.

· public ByteArrayInputStream(byte[] buf)
Конструктор аналогичен предыдущему при условии ByteArrayInputStream(buf, 0, buf.length)

Ввод данных из потока ByteArrayInputStream никогда не блокируется.

В составе класса ByteArrayOutputStream предусмотрены средства динамического наращивания объёма массива типа byte, получающего выводимые данные. Перечислим конструкторы и методы класса.

· public ByteArrayOutputStream()
Создаёт объект потока ByteArrayOutputStream, предусматривающий вывод данных в массив типа byte с размером, предусмотренным по умолчанию.

· public ByteArrayOutputStream(int size)
Создаёт объект потока ByteArrayOutputStream, предусматривающий вывод данных в массив типа byte заданного размера size.

· public byte[] toByteArray()
Возвращает копию массива байтов, ранее выведенных потоком

· public int size()
Возвращает значение количества байтов, ранее выведенных потоком.

· public void reset()
Очищает буфер – массив потока, позволяя использовать его заново.

· public String toString()
Возвращает текущее содержимое буфера массива в виде объекта типа String, преобразуя байты в символы в соответствии с кодировкой символов, принятой по умолчанию.

· public String toString(String enc) throws UnsupportedEncodingException
Возвращает текущее содержимое буфера – массива в виде объекта типа String, преобразуя байты в символы в соответствии с кодировкой символов, заданной строкой enc. Если указанная кодировка не поддерживается, выбрасывается исключение типа UnsupportedEncodingException.

· public void writeTo(OutputStream out) throws IOException
Выводит содержимое массива – буфера в заданный поток out.

Если ByteArrayOutputStream используется в качестве получателя данных, выводимых из «внешних» фильтрованных потоков, прежде чем обратиться к методу toByteArray, следует выполнить операцию сброса (flush) фильтрованных потоков.











Дата: 2019-02-19, просмотров: 239.