Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 сериализация».
Предыдущая статья — «Java 8 исключения».
Содержание
— Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.InputStream
— Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.OutputStream
— java.io.FileInputStream и java.io.FileOutputStream
— java.io.ByteArrayInputStream и java.io.ByteArrayOutputStream
— java.io.FilterInputStream и java.io.FilterOutputStream
— java.io.DataInputStream и java.io.DataOutputStream
— java.io.BufferedInputStream и java.io.BufferedOutputStream
— java.io.PipedInputStream и java.io.PipedOutputStream
— java.io.ObjectInputStream и java.io.ObjectOutputStream
— Диаграмма классов, показывающая иерархию основных дочерних классов для java.io.Reader
— Диаграмма классов, показывающая иерархию основных дочерних классов для java.io.Writer
— java.util.Scanner и java.io.PrintStream
Введение
Поток ввода/вывода (I/O Stream) представляет собой источник данных или место их назначения. Потоки могут представлять собой абсолютно различные источники и места назначения: файлы на диска, устройства, сеть, другие программы, массивы в памяти т. д.
Потоки поддерживают большое количество различных типов данных: байты, примитивные типы, локализованные символы, объекты. Некоторые потоки просто передают данные, другие изменяют в соответствии со своими потребностями.
Независимо от внутреннего устройства потоки представляют собой одинаковую модель для программы. Поток представляет собой последовательность данных.
Потоки байт
Все классы, работающие с потоками байт, наследуются от абстрактных классов java.io.InputStream или java.io.OutputStream.
Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.InputStream
Диаграмма классов, показывающая иерархию основных дочерних классов для класса java.io.OutputStream
Принцип работы с каждым из этих классов весьма схож. Важно знать методы
java.io.InputStream и
java.io.OutputStream, поскольку они наследуются в каждом из этих классов.
java.io.InputStream
Абстрактный класс, являющийся базовым классом для всех классов, представляющий поток ввода.
1 2 |
public int available() throws IOException |
Возвращает количество байт, которое может быть прочитано из потока без блокировки. Некоторые реализации
InputStream возвращают полное количество байт в потоке, но не все. Не стоит использовать этот метод для определения размера буфера, который будет хранить все данные из потока.
1 2 |
public void close() throws IOException |
Закрывает поток и освобождает все ресурсы.
1 |
public void mark(int readlimit) |
Помечает текущую позицию во входной строке. Работает только если
markSupported() возвращает
true. Смысл этого метода в том, что поток каким-нибудь образом запоминает все считанные после вызова этого метода данные и может вернуть те же самые данные ещё раз после вызова метода
reset(). Если после вызова метода
mark(int readLimit) из потока было прочитано больше
readLimit байт, то поток не обязан запоминать что бы то ни было.
1 2 |
public void reset() throws IOException |
Если метод markSupported() возвращает true, то:
- Если метод mark() не был вызван ни разу, либо количество байт, которые были прочитаны из потока после вызова mark() , больше аргумента метода mark() в последнем его вызове, то может броситься исключение IOException.
- Если исключение IOException не было брошено, то поток возвращается в такое состояние, что все вызовы методов read() в дальнейшем будут возвращать те же данные, которые они возвращали с момента последнего вызова метода mark() (либо с начала потока, если метод mark() не был вызван ни разу).
Если метод markSupported() возвращает false, то:
- Вызов метода reset() может бросить исключение IOException.
- Если не бросается исключение IOException, то поток сбрасывается в фиксированное состояние, которое зависит от конкретного типа входного потока, и как он был создан. Байты, которые будут прочитаны при последующих вызовах методов read(), зависят от конкретного типа входной строки.
1 |
public boolean markSupported() |
Возвращает
true, если реализация
InputStream поддерживает методы mark() и reset().
1 2 |
public abstract int read() throws IOException |
Считывает один байт из потока. Возвращает его в
int, содержащем значение от 0 до 255. Возвращает -1, если достигли конца потока. Блокирует выполнение текущего потока программы до тех пор, пока не появятся входные данные, не достигнется конец потока, либо бросится исключение.
1 2 |
public int read(byte[] b) throws IOException |
Считывает некоторое количество байт из входного потока и сохраняет его в массив байт b. Возвращает количество считанных байт, которое может быть меньше длины массива. Метод блокирует выполнение текущего потока программы до тех пор, пока не появятся входные данные, не достигнется конец потока, либо бросится исключение.
Если длина массива b равна нулю, то байты не считываются и возвращается 0, в противном случае происходит попытка считать хотя бы один байт. Если достигнут конец потока, то возвращается -1.
Метод
read(b) у класса
InputStream имеет такой же эффект, что и
read(b, 0, b.length), но дочерние классы могут переопределить его, если нужно.
1 2 3 4 |
public int read(byte[] b, int off, int len) throws IOException |
Читает до len байт из входного потока в массив байт. Пытается считать len байт, но может считать и меньше. Количество реально считанных байт возвращается как int .
Этот метод блокирует выполнение текущего потока программы до тех пор, пока не появятся данные, не будет достигнут конец потока, либо возникнет исключение.
Если len равен нулю, то байты не считываются, и возвращается 0. В противном случае происходит попытка считать хотя бы один байт. Если никаких байт нет, так как был достигнут конец потока, то возвращается -1, иначе хотя бы один байт считывается и сохраняется в b.
Первый байт считывается в b[off] , второй в b[off + 1] и так далее.
Реализация этого метода в классе
InputStream просто вызывает метод
read() в цикле. Потомки могут переопределить это поведение на более оптимальное.
1 2 |
public long skip(long n) throws IOException |
Пропускает n следующих байт во входном потоке. Может пропустить меньшее количество байт по какой-нибудь причине. Возвращается реальное количество пропущенных байт.
java.io.OutputStream
Абстрактный класс, являющийся базовым классов для классов, реализующих выходной поток байт:
Основные методы:
1 2 |
public void close() throws IOException |
Закрывает выходной поток и освобождает ресурсы.
1 2 |
public void flush() throws IOException |
Записывает все байты из буфера. Некоторые реализации выходного потока могут накапливать байты в буфере и лишь потом реально записывать их. Вызов этого методы принудительно записывает данные из буфера и очищает его.
1 2 |
public abstract void write(int b) throws IOException |
Записывает байт в выходной поток.
1 2 |
public void write(byte[] b) throws IOException |
Записывает
b.length байт из указанного массива байт в выходной поток. Аналогично вызову
write(b, 0, b.length).
1 2 3 4 |
public void write(byte[] b, int off, int len) throws IOException |
Записывает len байт из массива байт, начиная с off , в выходной поток. Реализация этого метода в OutputStream вызывает в цикле метод write(int b). Дочерние классы могут переопределить его, дав более оптимальную реализацию.
java.io.FileInputStream и java.io.FileOutputStream
Предназначены для чтения и записи данных в файл и из файла. Пример использования:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import java.io.InputStream; import java.io.OutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; class Main { public static void main(String[] args) { try (InputStream is = new FileInputStream("input.txt"); OutputStream os = new FileOutputStream("output.txt")) { int bytesReaded; final int BUFFER_SIZE = 10_000; byte[] buff = new byte[BUFFER_SIZE]; while ((bytesReaded = is.read(buff)) != -1) { os.write(buff, 0, bytesReaded); } } catch (IOException ioex) { ioex.printStackTrace(); } } } |
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы этих классов.
java.io.ByteArrayInputStream и java.io.ByteArrayOutputStream
Класс ByteArrayInputStream позволяет создать входной поток, который будет считывать данные из массива байт. Класс ByteArrayOutputStream позволяет записывать данные в поток, а по окончании получить записанные данные в виде массива байт с помощью метода toByteArray(). Принцип работы с этими классами такой же, как и с остальными наследниками java.io.InputStream и java.io.OutputStream.
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы и методы этих классов.
java.io.FilterInputStream и java.io.FilterOutputStream
Базовые классы для потоков, которые содержат внутри себя другой поток и производят некую трансформацию записываемых и считываемых данных.
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы и методы этих классов.
java.io.DataInputStream и java.io.DataOutputStream
Классы DataInputStream и DataOutputStream позволяют платформонезависимо записывать в поток и считывать из потока примитивные типы языка Java. Класс DataInputStream реализует интерфейс DataInput, который содержит методы для чтения примитивных типов, а класс DataOutputStream реализует интерфейс DataOutput, который содержит методы для записи примитивных типов. Эти классы используют в качестве обёртки над другими потоками, например так:
1 |
DataInputStream dis = new DataInputStream(new FileInputStream("myfile.data")); |
Методы интерфейса DataInput используют исключение java.io.EOFException для обозначения конца потока, в отличие от методов класса InputStream, которые возвращают -1.
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы этих классов.
java.io.BufferedInputStream и java.io.BufferedOutputStream
Классы BufferedInputStream и BufferedOutputStream используют буфер, чтобы не нагружать систему операцией считывания и записи при каждом вызове методов write и read.
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы этих классов.
java.io.PipedInputStream и java.io.PipedOutputStream
Экземпляр класса PipedInputStream должен быть связан с экземпляром класса PipedOutputStream с помощью метода connect(PipedOutputStream src). С помощью PipedInputStream считываются данные, которые в другом потоке записываются в PipedOutputStream.
В диаграмме наследников InputStream и диаграмме наследников OutputStream показаны конструкторы этих классов.
java.io.ObjectInputStream и java.io.ObjectOutputStream
Классы ObjectInputStream и ObjectOutputStream позволяют считывать объекты из потока и записывать объекты в поток, то есть используются для сериализации и десериализации объектов.
Потоки символов
Все классы потоков символов наследуются от java.io.Reader или java.io.Writer. Как и у потоков байт есть два специализированных класса для файлового ввода/вывода: java.io.FileReader и java.io.FileWriter. Работа с потоками символов аналогична работе с потоками классов.
Любой поток байт можно превратить в поток символов, обернув его в java.io.InputStreamReader или в java.io.OutputStreamWriter для потока вывода.
1 2 3 |
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(byteArray), "windows-1251")) { // ... some code } |
С помощью класса java.io.BufferedReader можно считывать данные построчно, используя метод readLine() , который считает за конец строки символ '\n' (LF), '\r' (CR) или строку из двух символов "\r\n" (CR LF).
Диаграмма классов, показывающая иерархию основных дочерних классов для java.io.Reader
Диаграмма классов, показывающая иерархию основных дочерних классов для java.io.Writer
java.util.Scanner и java.io.PrintStream
Класс PrintStream позволяет записывать в поток форматированные данные. Особенно важны его методы printf
Класс Scanner позволяет считывать из текста форматированные данные.
Работа с этими классами несколько отличается от работы с большинством классов, описанных в этой статье. Я не буду из здесь описывать. Когда-нибудь я, скорее всего, напишу отдельную статью по ним.
RandomAccessFile
ИЗ ТЕКСТА
С помощью PipedOutputStream считываются данные, которые в другом потоке записываются в PipedOutputStream.
_
Опечатка?
Вроде бы должно быть
_
С помощью PipedInputStream считываются данные, которые в другом потоке записываются в PipedOutputStream.
Исправил, спасибо.
Еще 2 раза подряд встречается строка «OutputStream показаны конструкторы и методы этих классов.»
Исправил.
Есть такая система: Orpus.
https://orphus.ru/
Как раз для исправления опечаток в тексте.
Если планируете усовершенствовать ваш сайт, возможно, она будет полезна.
_
Спасибо за учебник.