Fileinputstream and bufferedinputstream in java
Excellent lesson! Very detailed! Very clear! Thank you! P/S: the more I learn from you, the more I find my university course on structured programming (using Java) a waste of money. But more importantly, the lack of clear explanation has made many students think that they are not capable of programming which is not true. The bad teaching cuts the dreams of many students short. And that cannot be measured by money.
To use BufferedInputStream does not only halve the time, but reduces it by a much larger amount. The two programs above that compare the speed of the two streams unfortunately add the slowness of the print() method to the measurement, and thus greatly distorts the final result. Let’s remove the print((char)i) method from the loop so that we can really only measure the speed of the read() methods. I read a 2.5MB (2.5 million bytes) file this way, and the result is: With FileInputStream: ~3100 ms, With BufferedInputStream: 110 ms. 30 times difference!
while((i=fileInputStream.read())!= -1) < System.out.print((char)i); >read() returns only one byte, and we are trying to print a char. How is it printing the char properly, shouldn’t it print a byte?
«So close no matter how far Couldn’t be much more from the heart Forever trusting who we are And nothing else matters» Sounds familiar somehow. is it a poem? LOL!
At the start of the FIleInputStream where it says «We read one byte from the file, convert the read bytes into files and display them on the console.» shouldn’t it be «convert the read bytes intro chars» ?
For some reason all these examples don’t seem to work in my IDE.I tried using a different filepath but got exceptions. Anyone else experiencing the same problem?
Потоки ввода, InputStream
Существуют две параллельные иерархии классов ввода : InputStream и Reader. Класс Reader введен в последних версиях Java. В данной статье рассматривается вопрос использования потока байтового ввода InputStream, иерархия которого представлена на следующем рисунке.
Поток Stream— это абстрактное понятие источника или приёмника данных, которые способны обрабатывать информацию. Есть два типа потоков: байтовые и символьные. В некоторых ситуациях символьные потоки более эффективны, чем байтовые. Классы, производные от базовых InputStream или Reader, имеют методы read() для чтения отдельных байтов или массива байтов.
Входной поток InputStream
Базовый класс InputStream — это абстрактный класс, определяющий входной поток данных, и является родителем для классов, получающих данные из различных источников : массив байтов, строки (String), файлы, каналы pipe, у которых одна из сторон является входом, а вторая сторона играет роль выхода, и т.д. Методы класса InputStream при возникновении ошибки вызывают исключение 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[]; ByteArrayInputStream bis1; 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; 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 bais; bais = new ByteArrayInputStream(buffer); try < BufferedInputStream bis; bis = new BufferedInputStream(bais); 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; 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; 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();