Потоки ввода, InputStream

Существуют две параллельные иерархии классов ввода : InputStream и Reader. Класс Reader введен в последних версиях Java. В данной статье рассматривается вопрос использования потоков для чтения файла. Иерархия входного потока InputStream представлена на следующем рисунке.

Иерархия InputStream

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

Входной поток InputStream

Базовый класс InputStream - это абстрактный класс, определяющий входной поток данных, и является родителем для классов, получающих данные из различных источников :

  • массив байт
  • строка (String)
  • файл
  • канал (pipe): данные помещаются с одного конца канала и извлекаются из другого
  • последовательность различных потоков, которые можно объединить в одном потоке
  • другие источники (например, подключение к интернету)

Все методы этого класса при возникновении ошибки вызывают исключение IOException.

Методы класса InputStream.

МетодОписание
int read() возвращает очередной доступный символ во входном потоке в виде целого
int read(byte b[]) чтение b.length байтов из входного потока в массив b. Возвращает количество прочитанных из потока байтов
int read(byte b[], int off, int len) чтение len байтов в массиве b, начиная со смещения off. Возвращает количество реально прочитанных байтов
long skip(long n) пропуск во входном потоке n байтов. Возвращает количество пропущенных байтов
int available() получение количество доступных для чтения байтов
void close() закрытие источник ввода. Последующие попытки чтения из этого потока вызывают IOException
void mark(int readlimit) установка метки в текущей позиции входного потока, которую можно будет использовать до тех пор, пока из потока не будет прочитано readlimit байтов
void reset() перевод указателя потока на установленную ранее метку
boolean markSupported() проверка поддержки потоком операции mark/reset

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

ByteArrayInputStream

Класс ByteArrayInputStream использует байтовый массив в качестве источника данных. Он имеет следующие конструкторы :

ByteArrayInputStream(byte[] buf)
ByteArrayInputStream(byte[] buf, int offset, int length)

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

Пример чтения массив байтов в консоль:

import java.io.ByteArrayInputStream;
 
public class TestBIS
{
    public static void main(String[] args)
    {
        byte[] array1 = new byte[]{1, 3, 5, 7};
        ByteArrayInputStream bis1 = new ByteArrayInputStream(array1);
        int b;
        while((b = bis1.read()) != -1)
            System.out.println(b);
         
        String text = "Hello world!";
        byte[] array2 = text.getBytes();
        ByteArrayInputStream bis2 = new ByteArrayInputStream(array2, 0, 5);
        while((b = bis2.read()) != -1)
            System.out.println((char)b);
    }
}

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

FileInputStream

FileInputStream - основной класс из данной иерархии для работы с файлами. Имеет два основных конструктора.

FileInputStream(File file) throws FileNotFoundException
FileInputStream(String name) throws FileNotFoundException

Подробно FileInputStream описан на странице Файлы и директории

FilterInputStream

FilterInputStream - абстрактный класс, предоставляющий интерфейс для классов-надстроек, которые добавляют к существующим потокам полезные свойства. FilterInputStream является базовым классом для двух других классов. Его единственный конструктор требует передачи в качестве параметра объекта класса InputStream, т.е. фактически объекта некоторого неабстрактного класса, порожденного от InputStream.

Прямое использование FilterInputStream в программе нецелесообразно.

BufferedInputStream

BufferedInputStream служит для организации более эффективного "буферизованного" ввода данных. Буферизация ввода-вывода является удобным способом оптимизации производительности, позволяя заключить в оболочку любой поток класса InputStream.

import java.io.*;
 
public class TestBufferedInputStream
{
    public static void main(String[] args)
    {
        String text = "Hello world!";
        byte[] buffer = text.getBytes();
        ByteArrayInputStream in = new ByteArrayInputStream(buffer);
         
        try {
            BufferedInputStream bis = new BufferedInputStream(in); 
            int c;
            while((c = bis.read()) != -1){
                System.out.print((char)c);
            }
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }
    } 
}

В конструкторе класса BufferedInputStream необходимо передать InputStream. В данном случае таким объектом является экземпляр класса ByteArrayInputStream.

Как и все потоки ввода BufferedInputStream обладает методом read(), который считывает данные с помощью метода read из массива buffer.

Фактические все то же самое можно было сделать и с помощью одного ByteArrayInputStream, не прибегая к буферизированному потоку. Класс BufferedInputStream просто оптимизирует производительность при работе с потоком ByteArrayInputStream.

DataInputStream

Для чтения байтовых данных (не строк) применяется класс DataInputStream. В этом случае необходимо использовать классы из группы InputStream. Для преобразования строки в массив байтов, пригодный для помещения в поток ByteArrayInputStream, в классе String предусмотрен метод getBytes(). Полученный ByteArrayInputStream представляет собой поток InputStream, подходящий для передачи DataInputStream.

При побайтовом чтении символов из форматированного потока DataInputStream методом readByte() любое полученное значение будет считаться действительным, поэтому возвращаемое значение неприменимо для идентификации конца потока. Вместо этого можно использовать метод available(), который сообщает, сколько еще осталось символов.

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

Конструктор класса DataInputStream:

DataInputStream(InputStream stream)

Методы DataInputStream

МетодОписание
boolean readBoolean() байт булевого однобайтового значения
byte readByte() байт одного байта
char readChar() байт значения char
double readDouble() байт восьмибайтового значения double
float readFloat() чтение четырехбайтового значения float
int readInt() чтение целочисленного значения int
long readLong() чтение значения long
short readShort() чтение значения short
String readUTF() чтение строки в кодировке UTF-8
int skipBytes(int n) пропуск при чтении n байтов

Пример чтения из бинарного файла с использованием DataInputStream

import java.io.*;
 
public class TestDataInputStream
{
    public static void main(String[] args)
    {
        // Считывание из бинарного файла data.bin объекта типа Person
        try {
            DataInputStream dis = new DataInputStream(new FileInputStream("data.bin")

            String name     = dis.readUTF();
            int    age      = dis.readInt();
            double height   = dis.readDouble();
            boolean married = dis.readBoolean();
            System.out.printf("Человека зовут: %s ; его возраст: %d , его рост: %f метров, женат/замужем: %b", 
                               name, age, height, married);
        } catch(IOException ex) {
            System.out.println(ex.getMessage());
        }
   } 
}

ObjectInputStream

Класс ObjectInputStream отвечает за чтение ранее сериализованных данных из потока. В конструкторе он принимает ссылку на поток ввода:

ObjectInputStream(InputStream in)

Основные методы класса ObjectInputStream :

МетодОписание
int read() чтение одного байта; возвращает его целочисленное представление
boolean readBoolean() чтение одного значения boolean
byte readByte() чтение одного байта
char readChar() чтение одного символ char
double readDouble() чтение значения типа double
float readFloat() чтение значения типа float
int readInt() чтение целочисленного значения int
long readLong() чтение значения типа long
short readShort() чтение значения типа short
String readUTF() чтение строки в кодировке UTF-8
Object readObject() чтение объекта
int skipBytes(int len) пропуск при чтении нескольких байт, количество которых равно len
int available() чтение количества доступных для чтения байт
void close() закрытие потока

Пример чтения объекта Person из файла :

import java.io.*;
 
public class TestObjectInputStream
{
    public static void main(String[] args)
    {
        try {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"));
            Person person = (Person) ois.readObject();
            System.out.printf("Имя: %s \t Возраст: %d \n", person.name, person.age);
        }
        catch(Exception e) {
            System.out.println(e.getMessage());
        } 
    } 
    class Person implements Serializable
    {
        private static final long serialVersionUID = 1L;
		
        public String name;
        public int age;
        public double height;
        public boolean married;
         
        public Person(String n, int a, double h, boolean m)
        {
            this.name    = n;
            this.height  = h;
            this.age     = a;
            this.married = m;
        }
    }
}

Класс PipedInputStream

Класс PipedInputStream - это специальный класс, используемый для связи отдельных программ (потоков) друг с другом внутри одной JVM. Данный класс является важным инструментом организации синхронизации потоков.

Конструкторы PipedInputStream :

PipedInputStream()
PipedInputStream(int pipeSize)
PipedInputStream (PipedOutputStream src)
PipedInputStream (PipedOutputStream src, int pipeSize)

Методы PipedInputStream :

  • available()
  • close()
  • connect (PipedOutputStream src)
  • read()
  • read(byte[] b, int off, int len)
  • receive(int b)

Пример простого использования PipedInputStream :

InputStream input = new PipedInputStream (pipedOutputStream);

int data = input.read();
while(data != -1) {
    // обработка данных в отдельном методе doSomethingWithData
    doSomethingWithData(data);

    data = input.read();
}
input.close();

Наверх
  Рейтинг@Mail.ru