JavaRush /Курсы /Java Core /Потоки для ввода/вывода файлов

Потоки для ввода/вывода файлов

Java Core
8 уровень , 2 лекция
Открыта

— А начнем мы с потоков для ввода/вывода файлов. Но обо всем по порядку.

Для чтений и записи файлов есть два класса:  FileInputStream и FileOutputStream. Как ты уже, наверное, догадался,  FileInputStream позволяет последовательно читать из файла байты, а FileOutputStream – записывать в файл байты. Вот какие методы есть у этих классов:

Метод Что метод делает
FileInputStream(String fileName);
— это конструктор. Позволяет указать имя файла на диске, из которого созданный объект будет читать данные.
int read();
— метод читает один байт из файла и возвращает его как результат. Тип результата расширяется до int.
int available();
— метод возвращает количество непрочитанных (доступных) байт.
void close();
— метод «закрывает» поток, вызывается после окончания работы с потоком.
Объект выполняет служебные операции, связанные с закрытием файла на диске и т.д.
Из потока больше нельзя читать данные.

Давай ради интереса посчитаем сумму всех байт в файле на диске. Вот как будет выглядеть этот код:

Подсчет суммы всех байт файла на диске
public static void main(String[] args) throws Exception
{
 //создаем объект FileInputStream, привязанный к файлу «c:/data.txt».
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 long sum = 0;

 while (inputStream.available() > 0) //пока остались непрочитанные байты
 {
  int data = inputStream.read(); //прочитать очередной байт
  sum += data; //добавить его к общей сумме 
 }
 inputStream.close(); // закрываем поток

 System.out.println(sum); //выводим сумму на экран. 
}

— Мы уже раньше что-то подобное разбирали. А как устроен FileOutputStream?

— Ок. Вот, смотри:

Метод Что метод делает
FileOutputStream (String fileName);

— это конструктор. Позволяет указать имя файла на диске, в который созданный объект будет писать данные.

void write(int data);

— метод записывает очередной байт, обрезая переменную data до одного байта.

void flush();

— часто данные для записи сначала собираются в большие блоки в памяти, а потом только пишутся на диск.

Команда flush требует немедленно записать всю несохраненную информацию на диск.

void close();

— метод «закрывает» поток, вызывается после окончания работы с потоком.

Объект выполняет служебные операции, связанные с закрытием файла на диске и т.д.

В поток больше нельзя писать данные, flush при этом вызывается автоматически.

— И все?

— Да, тут фактически только один метод для записи – write, который записывает только один байт за раз. Но благодаря ему можно записать в файл сколько угодно информации.

Программирование – это процесс разбиения одной большой и сложной задачи на много маленьких. Тут происходит практически тот же процесс: чтение и запись больших данных маленькими порциями – по кусочкам – по одному байту.

Вот как можно скопировать файл на диске, пользуясь этими классами:

Копируем файл на диске
public static void main(String[] args) throws Exception
{
 //Создаем поток-чтения-байт-из-файла
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 // Создаем поток-записи-байт-в-файл
 FileOutputStream outputStream = new FileOutputStream("c:/result.txt");

 while (inputStream.available() > 0) //пока есть еще непрочитанные байты
 {
  int data = inputStream.read(); // прочитать очередной байт в переменную data
  outputStream.write(data); // и записать его во второй поток
 }

 inputStream.close(); //закрываем оба потока. Они больше не нужны.
 outputStream.close();
}

— Спасибо, Риша. Наконец-то понял, как на самом деле работает этот код.

Комментарии (325)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
9 июня 2025
Цитата из одной из прошлых лекций: "...Начиная с Java 5 классы FileInputStream и FileOutputStream стали считаться устаревшими. Поэтому для создания объектов-файлов рекомендуется использовать методы утилитного класса - java.nio.Files:

InputStream input = Files.newInputStream(Path.of("fileNames"));
OutputStream output = Files.newOutputStream(Path.of("FileName"));
"
Victor Уровень 30
13 мая 2025
Я померял файл этой програмулькой - получилось 3614, посмотрел в свойствах файла - 31 байт. Кто-то врёт.
Vitalii Shevchenko Уровень 30
27 мая 2025
Открой таблицу ASCII и пересчитай сам, все там правильно
Anonymous #3473304 Уровень 51
11 февраля 2025
оценка лекции: 5 из 5 динозавров.
{Java_Shark} Уровень 36
20 ноября 2024
++
12 октября 2024
write обрезает записываемую переменную до одного байта. А каким образом? По какому принципу он обрезает, если записываемая переменная больше байта? Сначала, с конца, с середины...?
6aHguTo Уровень 36
30 октября 2024
проходили в синтаксисе эту тему. кажись он забирает последние 8 бит (1 байт), остальные отбрасывает. int это 8 байт или 32 бит (вспоминает побитовые операции) 32 нолика в рядок, последние 8 штук это и есть наш байт))
Jsuccess Уровень 30
3 декабря 2024
Берется восемь младших битов, остальные отбрасываются.
Private Joker Уровень 36
20 мая 2024
Почему нельзя было сначала давать эти лекции, когда изучали потоки?
3 июня 2024
помнишь опросник когда создавал акк в джавараш. Некоторые выбирают андроид или бэкенд и у них первый квест короче. Походу ты выбрал незнаю и тебе в первом квесте дали все сразу, но создателям этого сайта было лень переделывать квесты
Никита Онучин Уровень 32
2 мая 2024
Несколько вопросов: 1. Зачем метод write принимает аргумент int, если всё равно обрезает до байта? Почему не использован тип byte? 2. Зачем нужен метод .flush? write не сразу пишет байт в файл?
Private Joker Уровень 36
20 мая 2024
GPT дает очень хорошие ответы на эти вопросы. И спойлер, flush реально лучше
Serge Уровень 29
29 апреля 2024
Интересно, а можно вместо этого while (inputStream.available() > 0) //пока есть еще непрочитанные байты { int data = inputStream.read(); // прочитать очередной байт в переменную data outputStream.write(data); // и записать его во второй поток } сразу while (inputStream.available() > 0) //пока есть еще непрочитанные байты { outputStream.write(nputStream.read()); // прочитать очередной байт и записать его во второй поток }
Private Joker Уровень 36
20 мая 2024
ниже читабельность кода.
Измаил Зонов Уровень 32
29 февраля 2024
Для меня до сих пор остается непонятным один вопрос, а именно работа с байтами, я неоднократно сталкивался с проблемами в выводе, и еще другими, когда надо считать что в файле, а он выдает какие то непонятные цифры. Как преобразовывать информацию в нормальный вид после считывания байтами? Может я что то и глупое написал) но исходя из опыта задаю вопрос)
Енот Уровень 51 Expert
20 марта 2024
как я понял, не знаю на сколько это правильно. допустим есть текстовый файл и в нем строка "abc" коды символов соответственно 97 98 99 информация в файле хранится в двоичном виде, в виде 0 и 1 следовательно переводим 97 98 и 99 в двоичную систему счисления 1100001 - 97 1100010 - 98 1100011 - 99 1 байт это 8 бит, Добиваем нулями эти числа слева до 8 бит. следовательно, наш файл представляет из себя 01100001|01100010|01100011 соответственно, когда читаем из файла побайтово, то мы читаем пачками по 8 бит 01100001|01100010|01100011 размер файла в байтах это и есть количество этих групп по 8 бит метод available() соответственно возвращает количество этих групп, а когда мы суммируем байты, то никакой смысловой нагрузки это не несет. это просто сумма каких-то чисел. а чтоб отобразить потом это в консоли например, то просто конвертировать к чару каждый байт, например (char) 97
Serge Уровень 29
29 апреля 2024
А пробелы тоже считываются?
Максим Li Уровень 40
3 февраля 2024
4.02.2024