Ввод-вывод данных: классы FileInputStream, FileOutputStream

🔥 🚀 Важно для всех, кто работает с 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 Code

FileInputStream считывает файл размером 1,5 МБ за ~3500 миллисекунд, а BufferedInputStream – за ~1700 миллисекунд, что в два раза быстрее!

Перевод статьи «Input/output in Java. FileInputStream, FileOutputStream, and BufferedInputStream classes».

Оставьте комментарий

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

Прокрутить вверх