Что такое inputstream и outputstream java
Перейти к содержимому

Что такое inputstream и outputstream java

  • автор:

Потоки ввода-вывода. Работа с файлами

Отличительной чертой многих языков программирования является работа с файлами и потоками. В Java основной функционал работы с потоками сосредоточен в классах из пакета java.io .

Ключевым понятием здесь является понятие потока . Хотя понятие «поток» в программировании довольно перегружено и может обозначать множество различных концепций. В данном случае применительно к работе с файлами и вводом-выводом мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т.д.).

Поток связан с реальным физическим устройством с помощью системы ввода-вывода Java. У нас может быть определен поток, который связан с файлом и через который мы можем вести чтение или запись файла. Это также может быть поток, связанный с сетевым сокетом, с помощью которого можно получить или отправить данные в сети. Все эти задачи: чтение и запись различных файлов, обмен информацией по сети, ввод-ввывод в консоли мы будем решать в Java с помощью потоков.

Объект, из которого можно считать данные, называется потоком ввода , а объект, в который можно записывать данные, — потоком вывода . Например, если надо считать содержание файла, то применяется поток ввода, а если надо записать в файл — то поток вывода.

В основе всех классов, управляющих потоками байтов, находятся два абстрактных класса: InputStream (представляющий потоки ввода) и OutputStream (представляющий потоки вывода)

Но поскольку работать с байтами не очень удобно, то для работы с потоками символов были добавлены абстрактные классы Reader (для чтения потоков символов) и Writer (для записи потоков символов).

Все остальные классы, работающие с потоками, являются наследниками этих абстрактных классов. Основные классы потоков:

Классы потоков в Java

Потоки байтов

Класс InputStream

Класс InputStream является базовым для всех классов, управляющих байтовыми потоками ввода. Рассмотрим его основные методы:

  • int available() : возвращает количество байтов, доступных для чтения в потоке
  • void close() : закрывает поток
  • int read() : возвращает целочисленное представление следующего байта в потоке. Когда в потоке не останется доступных для чтения байтов, данный метод возвратит число -1
  • int read(byte[] buffer) : считывает байты из потока в массив buffer. После чтения возвращает число считанных байтов. Если ни одного байта не было считано, то возвращается число -1
  • int read(byte[] buffer, int offset, int length) : считывает некоторое количество байтов, равное length, из потока в массив buffer. При этом считанные байты помещаются в массиве, начиная со смещения offset, то есть с элемента buffer[offset] . Метод возвращает число успешно прочитанных байтов.
  • long skip(long number) : пропускает в потоке при чтении некоторое количество байт, которое равно number
Класс OutputStream

Класс OutputStream является базовым классом для всех классов, которые работают с бинарными потоками записи. Свою функциональность он реализует через следующие методы:

  • void close() : закрывает поток
  • void flush() : очищает буфер вывода, записывая все его содержимое
  • void write(int b) : записывает в выходной поток один байт, который представлен целочисленным параметром b
  • void write(byte[] buffer) : записывает в выходной поток массив байтов buffer.
  • void write(byte[] buffer, int offset, int length) : записывает в выходной поток некоторое число байтов, равное length , из массива buffer , начиная со смещения offset , то есть с элемента buffer[offset] .

Абстрактные классы Reader и Writer

Абстрактный класс Reader предоставляет функционал для чтения текстовой информации. Рассмотрим его основные методы:

  • absract void close() : закрывает поток ввода
  • int read() : возвращает целочисленное представление следующего символа в потоке. Если таких символов нет, и достигнут конец файла, то возвращается число -1
  • int read(char[] buffer) : считывает в массив buffer из потока символы, количество которых равно длине массива buffer. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
  • int read(CharBuffer buffer) : считывает в объект CharBuffer из потока символы. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
  • absract int read(char[] buffer, int offset, int count) : считывает в массив buffer, начиная со смещения offset, из потока символы, количество которых равно count
  • long skip(long count) : пропускает количество символов, равное count. Возвращает число успешно пропущенных символов

Класс Writer определяет функционал для всех символьных потоков вывода. Его основные методы:

  • Writer append(char c) : добавляет в конец выходного потока символ c. Возвращает объект Writer
  • Writer append(CharSequence chars) : добавляет в конец выходного потока набор символов chars. Возвращает объект Writer
  • abstract void close() : закрывает поток
  • abstract void flush() : очищает буферы потока
  • void write(int c) : записывает в поток один символ, который имеет целочисленное представление
  • void write(char[] buffer) : записывает в поток массив символов
  • absract void write(char[] buffer, int off, int len) : записывает в поток только несколько символов из массива buffer. Причем количество символов равно len, а отбор символов из массива начинается с индекса off
  • void write(String str) : записывает в поток строку
  • void write(String str, int off, int len) : записывает в поток из строки некоторое количество символов, которое равно len, причем отбор символов из строки начинается с индекса off

Функционал, описанный классами Reader и Writer, наследуется непосредственно классами символьных потоков, в частности классами FileReader и FileWriter соответственно, предназначенными для работы с текстовыми файлами.

Теперь рассмотрим конкретные классы потоков.

Потоки вывода, OutputStream

Стандартная библиотека Java имеет весьма развитые средства вывода данных. Все возможности вывода данных сосредоточены в пакете java.io.

Существуют две параллельные иерархии классов вывода : OutputStream и Writer. Класс Writer введен в последних версиях Java.

В данной статье рассматривается вопрос использования потоков для вывода данных в файл. Иерархии выходных OutputStream потоков представлена на следующем рисунке.

Иерархия OutputStream

Поток Stream— это абстрактное значение источника или приёмника данных, которые способны обрабатывать информацию. Есть два типа потоков: байтовые и символьные. В некоторых ситуациях символьные потоки более эффективны, чем байтовые. Классы, производные от классов OutputStream или Writer, имеют методы с именами write() для записи одиночных байтов или массива байтов (отвечают за вывод данных).

Выходной поток OutputStream

Класс OutputStream — это абстрактный класс, определяющий байтовый поток вывода. Наследники данного класса определяют куда направлять данные: в массив байтов, в файл или канал. Из массива байт можно создать текстовую строку String.

Методы класса OutputStream :

  • void write(int b) записывает один байт в выходной поток. Аргумент этого метода имеет тип int, что позволяет вызывать write, передавая ему выражение, при этом не нужно выполнять приведение его типа к byte.
  • void write(byte b[]) записывает в выходной поток весь указанный массив байтов.
  • void write(byte b[], int off, int len) записывает в поток len байтов массива, начиная с элемента b[off].
  • void flush() очищает любые выходные буферы, завершая операцию вывода.
  • void close() закрывает выходной поток. Последующие попытки записи в этот поток будут возбуждать IOException.

Класс ByteArrayOutputStream

Класс ByteArrayOutputStream представляет поток вывода, использующий массив байтов в качестве места вывода. Чтобы создать объект данного класса, можно использовать один из его конструкторов :

ByteArrayOutputStream() ByteArrayOutputStream(int size)

Первый конструктор создает массив данных для хранения байтов длиной в 32 байта, а второй конструктор создает массив длиной size.

Примеры использования класса ByteArrayOutputStream :

import java.io.ByteArrayOutputStream; public class TestBOS < public static void main(String[] args) < ByteArrayOutputStream bos; bos = new ByteArrayOutputStream(); String text = "Hello World!"; byte[] buffer = text.getBytes(); try< bos.write(buffer); >catch(Exception e) < System.out.println(e.getMessage()); >// Преобразование массива байтов в строку System.out.println(bos.toString()); // Вывод в консоль по символьно byte[] array = bos.toByteArray(); for (byte b: array) < System.out.print((char)b); >System.out.println(); > >

В классе ByteArrayOutputStream метод write записывает в поток некоторые данные (массив байтов). Этот массив байтов записывается в объекте ByteArrayOutputStream в защищенное поле buf, которое представляет также массив байтов (protected byte[] buf). Так как метод write может вызвать исключение, то вызов этого метода помещается в блок try..catch.

Используя методы toString() и toByteArray(), можно получить массив байтов buf в виде текста или непосредственно в виде массива байт.

С помощью метода writeTo можно перенаправить массив байт в другой поток. Данный метод в качестве параметра принимает объект OutputStream, в который производится запись массива байт :

Для ByteArrayOutputStream не надо явным образом закрывать поток с помощью метода close.

Класс FileOutputStream

Класс FileOutputStream создаёт объект класса OutputStream, который можно использовать для записи байтов в файл. Это основной класс для работы с файлами. Создание нового объекта не зависит от того, существует ли заданный файл или нет. Если файл отсутствует, то будет создан новый файл. В случае попытки открытия файла, доступного только для чтения, будет вызвано исключение.

FileOutputStream имеет следующий конструкторы:

public FileOutputStream(File file) throws FileNotFoundException; public FileOutputStream(String name) throws FileNotFoundException; public FileOutputStream(String name, boolean append) throws FileNotFoundException;

Смысл конструкторов последнего понятен из их описания. Но имеется несколько нюансов :

  • При открытии файла на запись, если файл не существует, то он будет создан.
  • Если файл существует, то он будет полностью обновлен. Т.е. если открыть и сразу закрыть файл, то содержимое файла будет уничтожено; реальный файл на диске станет нулевой длины.
  • Исключением для предыдущего правила является последний из конструкторов. Если третьему параметру append присвоить значение true, то можно будет дописывать в конец файла.

Какой-либо дополнительной функциональности по сравнению с базовым классом FileOutputStream не добавляет.

ByteArrayOutputStream bos = new ByteArrayOutputStream(); String text = «Hello Wolrd!»; byte[] buffer = text.getBytes(); try < bos.write(buffer); >catch(Exception e) < System.out.println(e.getMessage()); >try < FileOutputStream fos = new FileOutputStream("hello.txt"); bos.writeTo(fos); >catch(IOException e)

Класс BufferedOutputStream

Класс BufferedOutputStream создает буфер для потоков вывода. Этот буфер накапливает выводимые байты без постоянного обращения к устройству. И когда буфер заполнен, производится запись данных.

import java.io.*; . String text = «Hello world!»; // строка для записи FileOutputStream fos = new FileOutputStream(«file.txt»); try < BufferedOutputStream bos = new BufferedOutputStream(fos); // Переводим текст в байты byte[] buffer = text.getBytes(); bos.write(buffer, 0, buffer.length); >catch(IOException e)

Класс BufferedOutputStream в конструкторе принимает в качестве параметра объект OutputStream — в примере это файловый поток вывода FileOutputStream.

BufferedOutputStream не добавляет много новой функциональности, он просто оптимизирует действие потока выводаи его следует использовать для организации более эффективного буферизованного вывода в поток.

Класс DataOutputStream

Класс DataOutputStream позволяет писать данные в поток через интерфейс DataOutput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.

Для записи каждого из примитивных типов предназначен свой метод класса DataOutputStream:

  • writeByte(int value) — записывает в поток 1 байт
  • writeChar(int value) — записывает 2х-байтовое значение char
  • writeInt(int value) — записывает в поток целочисленное значение int
  • writeShort(int v) — записывает в поток значение short
  • writeFloat(float value) — записывает в поток 4-байтовое значение float
  • writeDouble(double value) — записывает в поток 8-байтовое значение double
  • writeBoolean(boolean value) — записывает в поток булевое однобайтовое значение
  • writeLong(long value) — записывает в поток значение long
  • writeUTF(String value) — записывает в поток строку в кодировке UTF-8

import java.io.*; . FileOutputStream fos = new FileOutputStream(«c://data.bin»); // запись в файл try (DataOutputStream dos = new DataOutputStream(fos)) < // записываем значения dos.writeUTF("Киса Воробьянинов"); dos.writeInt(30); dos.writeDouble(20.58); dos.writeBoolean(falss); System.out.println("Запись в файл выполнена"); >catch(IOException e)

Класс PrintStream

PrintStream является именно тем классом, который используется для вывода информации в консоль. Когда мы с помощью вызова System.out.println() пишем в консоль некоторую информацию, то тем самым используется PrintStream, так как переменная out класса System представляет объект класса PrintStream, а метод println() — это метод класса PrintStream.

Но PrintStream можно использовать для записи информации в поток вывода. Например, запишем информацию в файл:

import java.io.*; . String text = «Hello, World!»; // строка для записи FileOutputStream fos = new FileOutputStream(«C:/data.txt»); try < PrintStream printStream = new PrintStream(fos)); printStream.println(text); System.out.println("Запись в файл выполнена"); >catch(IOException e)

В данном примере используется конструктор PrintStream, который в качестве параметра принимает поток вывода FileOutputStream. Можно было бы также использовать конструктор с указанием названия файла для записи: PrintStream (String filename).

С помощью метода println() производится запись информации в выходной поток — то есть в объект FileOutputStream. В случае с выводом на консоль с помощью System.out.println() в качестве потока вывода выступает консоль.

Для вывода информации в выходной поток PrintStream использует следующие методы:

println(): вывод строковой информации с переводом строки print(): вывод строковой информации без перевода строки printf(): форматированный вывод

Следующий код показывает возможности использования форматированного вывода класса PrintStream :

int i = 15; printStream.printf("Квадрат числа %d равен %d \n", i, i*i);

Класс ObjectOutputStream

Класс ObjectOutputStream используется для сериализации объектов в поток. Сериализация представляет процесс записи состояния объекта в поток, соответственно процесс извлечения или восстановления состояния объекта из потока называется десериализацией. Сериализация очень удобна, когда идет работа со сложными объектами.

Для создания объекта ObjectOutputStream необходимо в конструктор передать поток, в который будет производится запись объектов.

Для записи данных ObjectOutputStream использует ряд методов, среди которых можно выделить следующие:

Метод Описание
void close() закрывает поток
void flush() сбрасывает содержимое буфера в выходной поток и очищает его
void write(byte[] buf) записывает в поток массив байтов
void write(int val) записывает в поток один младший байт из val
void writeBoolean(boolean val) записывает в поток значение boolean
void writeByte(int val) записывает в поток один младший байт из val
void writeChar(int val) записывает в поток значение типа char, представленное целочисленным значением
void writeDouble(double val) записывает в поток значение типа double
void writeFloat(float val) записывает в поток значение типа float
void writeInt(int val) записывает целочисленное значение
void writeLong(long val) записывает значение типа long
void writeShort(int val) записывает значение типа short
void writeUTF(String str) записывает в поток строку в кодировке UTF-8
void writeObject(Object obj) записывает в поток отдельный объект

Представленные методы охватывают весь спектр данных, которые можно сериализовать.

Пример использования класса ObjectOutputStream :

import java.io.*; class Person implements Serializable < private static final long serialVersionUID = 1L; public String name ; public int age ; public double height ; public boolean married; Person(String name,int age,double height,boolean married) < this.name = name; this.age = age; this.height = height; this.married = married; >> public class Example < public static void main(String[] args) < FileOutputStream fos; fos = new FileOutputStream("c:/data/persons.dat"); try < ObjectOutputStream oos; Person person; oos = new ObjectOutputStream(fos); person = new Person("Остап Бендер",35,175,false); oos.writeObject (person); >catch(Exception e) < System.out.println(e.getMessage()); >> >

Необходимо принимать во внимание, что сериализовать можно только те объекты, которые реализуют интерфейс Serializable.

Класс PipedOutputStream

Пакет java.io содержит класс PipedOutputStream, который может быть подключен к PipedInputStream, используемый для установления связи между двумя каналами. Данные в PipedOutputStream передаются в потоке Thread, который отправляет их в подключенный PipedInputStream, где данные также читаются, но в другом потоке.

То есть, класс PipedOutputStream предназначен для передачи информации между программами через каналы (pipes).

Наиболее часто используемые методы класса PipedOutputStream :

  • void write(int b) — запись байта в канал
  • void write(byte[] bytes, int off, int len) — запись определенного количества len байт начиная со смещения off массив bytes
  • connect(PipedInputStream pis) — установление связи в каналом ввода pis
  • close() — закрытие канала
  • flush() — сброс данных в канал

Все методы класса могут вызвать исключение IOException.

Пример использования класса PipedOutputStream :

import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Example < public static void main(String[] args) < PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(); byte[] bytes = "Hello, World!".getBytes(); try < // Установление связи между "трубами" pos.connect(pis); // Запись данных в PipedOutputStream for (int i = 0; i < bytes.length; i++) pos.write(bytes[i]); // Чтение данных из PipedInputStream int c; while((c = pis.read() ) != -1) < System.out.print((char) c); >> catch (IOException ioe) < System.out.println(ioe); >> >

Что такое inputstream и outputstream java

На этом шаге мы рассмотрим классы InputStream

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *