🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!
Всем привет! Сегодня мы поговорим о потоках ввода-вывода в Java и обсудим особенности и применение классов FileInputStream, FileOutputStream и BufferedInputStream.

Язык Java предоставляет множество способов работы с вводом/выводом. В предыдущей статье мы рассмотрели, как получить данные из любого источника с помощью BufferedReader
, познакомились с абстрактными классами InputStream
, OutputStream
, а также с их некоторыми потомками. Сегодня мы обсудим 3 новых класса: FileOutputStream
, FileInputStream
и BufferedInputStream
.
Класс FileOutputStream
FileOutputStream
– это одна из реализаций абстрактного класса OutputStream
. Основное назначение – запись байтов в файл.
Этот класс в своём конструкторе позволяет указать файл для записи двумя способами: можно передать или путь к файлу, или сам объект File
.
Рассмотрим оба случая:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Run CodeПри создании объекта File
мы передали в конструктор нужный путь. Мы можем не создавать его заранее: если файла нет, программа создаст его автоматически.
Можно обойтись и без дополнительного объекта: достаточно передать строку с указанием пути, как это показано в примере ниже.
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Run CodeРезультат в обоих случаях будет одинаковым. Когда мы откроем файл, то увидим в нем следующее:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Однако есть нюанс. Если мы запустим код из примера несколько раз подряд, а затем откроем файл, то несмотря на неоднократный запуск кода увидим только одну строку: каждый раз данные перезаписываются.
Что делать, если нам нужно добавлять данные в конец файла к уже имеющимся строкам?
Выход есть! Конструктор FileOutputStream
может принимать дополнительный параметр – boolean append
. По умолчанию его значение равно false
, из-за чего старые данные стираются и заменяются новыми. Если же передать в параметр значение true
, то данные будут добавлены в конец файла.
Запустим наш модифицированный код:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Run CodeСодержание файла станет таким:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Совет: не забывайте использовать метод close()
, чтобы освободить ресурсы памяти.
Класс FileInputStream
Класс FileInputStream
, наоборот, производит чтение байтов из файла. Если FileOutputStream
наследует OutputStream
, то этот класс реализует InputStream
.
Напишем несколько строк текста в файле “test.txt”:
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"
Вот как выглядит чтение данных из файла с помощью FileInputStream
:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Run CodeНа каждой итерации цикла считывается из файла один байт. Далее мы преобразуем полученные байты в символы и выводим их в консоль. Вот что получилось:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
Класс BufferedInputStream
Чтение из файла – операция, требующая довольно много ресурсов, и считывать данные по одному байту крайне неэффективно. Оптимизировать операции ввода-вывода можно с помощью буферизации.
Класс BufferedInputStream
считывает данные сразу блоками, временно сохраняя их в специальном буфере, что позволяет нам сократить количество обращений к файлу.
Рассмотрим на примере:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Run CodeИтак, мы создаем объект класса BufferedInputStream
. Его конструктор принимает экземпляр класса InputStream
или любого его наследника, в том числе FileInputStream
.
В качестве дополнительного аргумента можно указать размер буфера в байтах. В нашем примере данные будут считываться по 200 байт за раз!
Для сравнения производительности можно взять большой текстовый файл на несколько мегабайт и посчитать, сколько времени в миллисекундах займет каждый из способов:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
Run CodeFileInputStream
считывает файл размером 1,5 МБ за ~3500 миллисекунд, а BufferedInputStream
– за ~1700 миллисекунд, что в два раза быстрее!
Перевод статьи «Input/output in Java. FileInputStream, FileOutputStream, and BufferedInputStream classes».