что такое байтовый поток как он реализован внутри java
Байтовые и символьные потоки ввода/вывода в java
При создании приложений всегда возникает необходимость прочитать информацию из какого-либо источника и сохранить результат. Действия по чтению/записи информации представляют собой стандартный и простой вид деятельности. Самые первые классы ввода/вывода связаны с передачей и извлечением последовательности байтов.
Потоки ввода последовательности байтов являются подклассами абстрактного класса InputStream, потоки вывода – подклассами абстрактного класса OutputStream. Эти классы являются суперклассами для ввода массивов байтов, строк, объектов, а также для выбора из файлов и сетевых соединений. При работе с файлами используются подклассы этих классов соответственно FileInputStream и FileOutputStream, конструкторы которых открывают поток и связывают его с соответствующим физическим файлом.
Для чтения байта или массива байтов используются абстрактные методы read() и read(byte[] b) класса InputStream. Метод возвращает –1, если достигнут конец потока данных, поэтому возвращаемое значение имеет тип int, не byte. При взаимодействии с информационными потоками возможны различные исключительные ситуации, поэтому обработка исключений вида try-catch при использовании методов чтения и записи является обязательной. В конкретных классах потоков ввода указанные выше методы реализованы в соответствии с предназначением класса. В классе FileInputStream данный метод читает один байт из файла, а поток System.in как встроенный объект подкласса InputStream позволяет вводить информацию с консоли. Абстрактный метод write(int b) класса OutputStream записывает один байт
в поток вывода. Оба эти метода блокируют поток до тех пор, пока байт не будет записан или прочитан. После окончания чтения или записи в поток его всегда следует закрывать с помощью метода close(), для того чтобы освободить ресурсы приложения.
Поток ввода связывается с одним из источников данных, в качестве которых могут быть использованы массив байтов, строка, файл, «pipe»-канал, сетевые соединения и др. Набор классов для взаимодействия с перечисленными источниками приведен на рис. 9.1.
Рис. 9.1. Иерархия классов байтовых потоков ввода
Абстрактный класс FilterInputStream используется как шаблон для настройки классов ввода, наследуемых от класса InputStream. Класс DataInputStream предоставляет методы для чтения из потока данных значений базовых типов, но начиная с версии 1.2 класс был помечен как deprecated и не рекомендуется к использованию. Класс BufferedInputStream присоединяет к потоку буфер для ускорения последующего доступа.
Для вывода данных используются потоки следующих классов.
Рис. 9.2. Иерархия классов байтовых потоков вывода
Абстрактный класс FilterOutputStream используется как шаблон для настройки производных классов. Класс BufferedOutputStream присоединяет буфер к потоку для ускорения вывода и уменьшения доступа к внешним устройствам.
Начиная с версии 1.2 пакет java.io подвергся значительным изменениям. Появились новые классы, которые производят скоростную обработку потоков, хотя и не полностью перекрывают возможности классов предыдущей версии.
Для обработки символьных потоков в формате Unicode применяется отдельная иерархия подклассов абстрактных классов Reader и Writer, которые почти полностью повторяют функциональность байтовых потоков, но являются более актуальными при передаче текстовой информации. Например, аналогом класса FileInputStream является класс FileReader. Такой широкий выбор потоков позволяет выбрать наилучший способ записи в каждом конкретном случае.
В примерах по возможности используются способы инициализации для различных семейств потоков ввода/вывода.
Рис. 9.3. Иерархия символьных потоков ввода/вывода
/* пример # 2 : чтение по одному байту (символу) из потока ввода : ReadDemo.java */
public class ReadDemo <
public static void main(String[] args) <
Байтовые потоки
1. Класс InputStream
Класс InputStream – это абстрактный класс. Все байтовые потоки чтения наследуются от класса InputStream.
Методы класса InputStream:
Существует 3 основных read() метода:
Методы read() будут блокированы, пока доступные данные не будут прочитаны.
2. Класс OutputStream
Все байтовые потоки записи наследуются от абстрактного класса OutputStream.
Методы класса OutputStream:
Существуют 3 основных write() метода:
3. Класс FileInputStream
Поток FileInputStream используется в Java для чтения данных из файла.
Конструкторы класса FileInputStream:
Представленный конструктор использует имя файла в качестве потока с целью создания объекта входного потока для считывания файла.
Этот конструктор использует объектный файл с целью создания объекта входного потока для чтения файла.
4. Класс FileOutputStream
В Javа FileOutputStream используется для создания файла и последующей записи в него. Поток создаст файл в случае его отсутствия перед его открытием для вывода.
Конструкторы класса FileOutputStream:
Представленный конструктор использует имя файла в качестве строки с целью создания объекта входного потока для записи файла в Java.
Этот конструктор использует объектный файл с целью создания объекта выходного потока для записи файла.
Java 8 потоки ввода/вывода
Содержание
Введение
Поток ввода/вывода (I/O Stream) представляет собой источник данных или место их назначения. Потоки могут представлять собой абсолютно различные источники и места назначения: файлы на диска, устройства, сеть, другие программы, массивы в памяти т. д.
Потоки поддерживают большое количество различных типов данных: байты, примитивные типы, локализованные символы, объекты. Некоторые потоки просто передают данные, другие изменяют в соответствии со своими потребностями.
Независимо от внутреннего устройства потоки представляют собой одинаковую модель для программы. Поток представляет собой последовательность данных.
Потоки байт
Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.InputStream
Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.OutputStream
java.io.InputStream
Абстрактный класс, являющийся базовым классом для всех классов, представляющий поток ввода.
Основные методы:
Возвращает количество байт, которое может быть прочитано из потока без блокировки. Некоторые реализации InputStream возвращают полное количество байт в потоке, но не все. Не стоит использовать этот метод для определения размера буфера, который будет хранить все данные из потока.
Закрывает поток и освобождает все ресурсы.
BestProg
Система ввода/вывода Java. Потоки. Байтовые потоки. Символьные потоки. Стандартные потоки
Содержание
Поиск на других ресурсах:
1. Общие понятия системы ввода/вывода Java. Поток. Определение потока
В языке программирования Java ввод/вывод информации базируется на понятии потока. Поток – это абстрактное понятие, которое символизирует источник или приемник данных, который может передавать или получать некоторую информацию. Любой поток скрывает операции над данными, которые выполняются на низших уровнях непосредственно в устройствах ввода/вывода.
Соответственно назначению потоков, классифицируются и классы в языке Java. Одни классы реализуют операции ввода, другие реализуют операции вывода. Чтобы использовать классы потоков ввода/вывода нужно импортировать пакет java.io
Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов поддерживается в паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.
2. Виды потоков в Java
В языке Java различают два вида потоков:
Классы, которые реализуют байтовые потоки ввода унаследованы от абстрактного класса InputStream :
Классы, которые реализуют байтовые потоки вывода унаследованы от абстрактного класса OutputStream :
4. Символьные потоки ввода/вывода. Обзор классов символьных потоков
Классы, которые предназначены для описания символьных потоков делятся на два вида:
Классы потоков ввода следующие:
Классы потоков вывода следующие:
Система ввода/вывода
Java имеет в своём составе множество классов, связанных с вводом/выводом данных. Рассмотрим некоторые из них.
Класс File
В отличие от большинства классов ввода/вывода, класс File работает не с потоками, а непосредственно с файлами. Данный класс позволяет получить информацию о файле: права доступа, время и дата создания, путь к каталогу. А также осуществлять навигацию по иерархиям подкаталогов.
Подробнее о классе java.io.File
Поток
Есть два типа потоков: байтовые и символьные. В некоторых ситуациях символьные потоки более эффективны, чем байтовые.
За ввод и вывод отвечают разные классы Java. Классы, производные от базовых классов InputStream или Reader, имеют методы с именами read() для чтения отдельных байтов или массива байтов (отвечают за ввод данных). Классы, производные от классов OutputStream или Write, имеют методы с именами write() для записи одиночных байтов или массива байтов (отвечают за вывод данных).
Подробнее о классе InputStream
Класс OutputStream
В этой категории находятся классы, определяющие, куда направляются ваши данные: в массив байтов (но не напрямую в String; предполагается что вы сможете создать их из массива байтов), в файл или канал.
BufferedOutputStream Буферизированный выходной поток ByteArrayOutputStream Создает буфер в памяти. Все данные, посылаемые в этот поток, размещаются в созданном буфере DataOutputStream Выходной поток, включающий методы для записи стандартных типов данных Java FileOutputStream Отправка данных в файл на диске. Реализация класса OutputStream ObjectOutputStream Выходной поток для объектов PipedOutputStream Реализует понятие выходного канала. FilterOutputStream Абстрактный класс, предоставляющий интерфейс для классов-надстроек, которые добавляют к существующим потокам полезные свойства.
BufferedOutputStream
Класс BufferedOutputStream не сильно отличается от класса OutputStream, за исключением дополнительного метода flush(), используемого для обеспечения записи данных в буферизируемый поток. Буферы вывода нужно для повышения производительности.
ByteArrayOutputStream
Класс ByteArrayOutputStream использует байтовый массив в выходном потоке. Метод close() можно не вызывать.
DataOutputStream
Класс DataOutputStream позволяет писать элементарные данные в поток через интерфейс DataOutput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.
Класс DataOutputStream расширяет класс FilterOutputStream, который в свою очередь, расширяет класс OutputStream.
Методы интерфейса DataOutput:
FileOutputStream
Класс FileOutputStream создаёт объект класса OutputStream, который можно использовать для записи байтов в файл. Создание нового объекта не зависит от того, существует ли заданный файл, так как он создаёт его перед открытием. В случае попытки открытия файла, доступного только для чтения, будет передано исключение.
Классы символьных потоков
Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode.
Reader
Методы класса Reader:
Класс BufferedReader
Класс BufferedReader увеличивает производительность за счёт буферизации ввода.
Класс CharArrayReader
Класс CharArrayReader использует символьный массив в качестве источника.
Класс FileReader
Класс FileReader, производный от класса Reader, можно использовать для чтения содержимого файла. В конструкторе класса нужно указать либо путь к файлу, либо объект типа File.
Writer
Класс BufferedWriter
Класс CharArrayWriter
Класс CharArrayWriter использует массив для выходного потока.
Класс FileWriter
Класс FileWriter создаёт объект класса, производного от класса Writer, который вы можете применять для записи файла. Есть конструкторы, которые позволяют добавить вывод в конец файла. Создание объекта не зависит от наличия файла, он будет создан в случае необходимости. Если файл существует и он доступен только для чтения, то передаётся исключение IOException.
Чтение и запись файлов
В filename нужно указать имя файла, который вы хотите открыть. Если при создании входного потока файл не существует, передаётся исключение FileNotFoundException. Аналогично для выходных потоков, если файл не может быть открыт или создан, также передаётся исключение. Сам класс исключения происходит от класса IOException. Когда выходной файл открыт, любой ранее существовавший файл с тем же именем уничтожается.
После завершения работы с файлом, его необходимо закрыть с помощью метода close() для освобождения системных ресурсов. Незакрытый файл приводит к утечке памяти.
В JDK 7 метод close() определяется интерфейсом AutoCloseable и можно явно не закрывать файл, а использовать новый оператор try-с-ресурсами, что для Android пока не слишком актуально.
Иногда используют вариант, когда метод close() помещается в блок finally. При таком подходе все методы, которые получают доступ к файлу, содержатся в пределах блока try, а блок finally используется для закрытия файла. Таким образом, независимо от того, как закончится блок try, файл будет закрыт.
Так как исключение FileNotFoundException является подклассом IOException, то не обязательно обрабатывать два исключения отдельно, а оставить только IOException, если вам не нужно отдельно обрабатывать разные причины неудачного открытия файла. Например, если пользователь вводит вручную имя файла, то более конкретное исключение будет к месту.
Для записи в файл используется метод write().
Метод пишет в файл байт, переданный параметром value. Хотя параметр объявлена как целочисленный, в файл записываются только младшие восемь бит. При ошибке записи передаётся исключение.
В JDK 7 есть способ автоматического управления ресурсами:
Когда в Android будет полноценная поддержка JDK 7, то дополним материал.
Чтобы открыть файл для посимвольного чтения, используется класс FileInputReader; имя файла задаётся в виде строки (String) или объекта File. Ускорить процесс чтения помогает буферизация ввода, для этого полученная ссылка передаётся в конструктор класса BufferedReader. Так как в интерфейсе класса имеется метод readLine(), все необходимое для чтения имеется в вашем распоряжении. При достижении конца файла метод readLine() возвращает ссылку null.
Объект FileWriter записывает данные в файл. При вводе/выводе практически всегда применяется буферизация, поэтому используется BufferedWriter.
Когда данные входного потока исчерпываются, метод readLine() возвращает null. Для потока явно вызывается метод close(); если не вызвать его для всех выходных файловых потоков, в буферах могут остаться данные, и файл получится неполным.
PrintWriter форматирует данные так, чтобы их мог прочитать человек. Однако для вывода информации, предназначенной для другого потока, следует использовать классы DataOutputStream для записи данных и DataInputStream для чтения данных.
Единственным надежным способом записать в поток DataOutputStream строку так, чтобы ее можно было потом правильно считать потоком DataInputStream, является кодирование UTF-8, реализуемое методами readUTF() и writeUTF(). Эти методы позволяют смешивать строки и другие типы данных, записываемые потоком DataOutputStream, так как вы знаете, что строки будут правильно сохранены в Юникоде и их будет просто воспроизвести потоком DataInputStream.
Метод writeDouble() записывает число double в поток, а соответствующий ему метод readDouble() затем восстанавливает его (для других типов также существуют подобные методы).
Работа с классом RandomAccessFile напоминает использование совмещенных в одном классе потоков DataInputStream и DataOutputStream (они реализуют те же интерфейсы DataInput и DataOutput). Кроме того, метод seek() позволяет переместиться к определенной позиции и изменить хранящееся там значение.
При использовании RandomAccessFile необходимо знать структуру файла. Класс RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8.
RandomAccessFile может открываться в режиме чтения («r») или чтения/записи («rw»). Также есть режим «rws», когда файл открывается для операций чтения-записи и каждое изменение данных файла немедленно записывается на физическое устройство.
Исключения ввода/вывода
В большинстве случаев у классов ввода/вывода используется исключение IOException. Второе исключение FileNotFoundException передаётся в тех случаях, когад файл не может быть открыт. Данное исключение происходит от IOException, поэтому оба исключения можно обрабатывать в одном блоке catch, если у вас нет нужды обрабатывать их по отдельности.