19.1. Java — Потоки ввода/вывода и работа с файлами и каталогами
Пакет java.io содержит почти каждый класс, который может потребоваться Вам для совершения ввода и вывода в Java. Все данные потоки представлены потоком ввода и адресом вывода. Поток в пакете java.io осуществляет поддержку различных данных, таких как примитивы, объекты, локализованные символы и т.д.
Содержание
Потоки
Потоки в Java определяются в качестве последовательности данных. Существует два типа потоков:
- InPutStream – поток ввода используется для считывания данных с источника.
- OutPutStream – поток вывода используется для записи данных по месту назначения.
Java предоставляет сильную, но гибкую поддержку в отношении ввода/вывода, связанных с файлами и сетями, однако в данном руководстве рассмотрены лишь базовые функции, связанные с потоками и вводом/выводом. Рассмотрим далее по порядку наиболее распространенные примеры.
Байтовый поток
Потоки байтов в Java используются для осуществления ввода и вывода 8-битных байтов. Не смотря на множество классов, связанных с потоками байтов, наиболее распространено использование следующих классов: FileInputStream и FileOutputStream. Ниже рассмотрен пример, иллюстрирующий использование данных двух классов для копирования из одного файла в другой.
Примечание по примеру: чтобы скопировать файл, необходимо в папке проекта создать файл file.txt с любым или пустым содержимым.
Пример
Теперь рассмотрим файл file.txt со следующим содержимым:
В качестве следующего шага необходимо скомпилировать java-программу и выполнить ее, что позволит создать файл copied_file.txt с тем же содержимым, что имеется в file.txt. Таким образом, разместим обозначенный код в файле FileCopy.java и выполним следующее действие:
Символьные потоки
Потоки байтов в Java позволяют произвести ввод и вывод 8-битных байтов, в то время как потоки символов используются для ввода и вывода 16-битного юникода. Не смотря на множество классов, связанных с потоками символов, наиболее распространено использование следующих классов: FileReader и FileWriter. Не смотря на тот факт, что внутренний FileReader использует FileInputStream, и FileWriter использует FileOutputStream, основное различие состоит в том, что FileReader производит считывание двух байтов в конкретный момент времени, в то время как FileWriter производит запись двух байтов за то же время.
Мы можем переформулировать представленный выше пример, в котором два данных класса используются для копирования файла ввода (с символами юникода) в файл вывода.
Примечание по примеру: чтобы скопировать файл, необходимо в папке проекта создать файл file.txt с любым или пустым содержимым.
Пример
Теперь рассмотрим файл file.txt со следующим содержимым:
В качестве следующего шага необходимо скомпилировать программу и выполнить ее, что позволит создать файл copied_file.txt с тем же содержимым, что имеется в file.txt. Таким образом, разместим обозначенный код в файле FileCopy.java и выполним следующее действие:
Стандартные потоки
Все языки программирования обеспечивают поддержку стандартного ввода/вывода, где программа пользователя может произвести ввод посредством клавиатуры и осуществить вывод на экран компьютера. Если вы знакомы с языками программирования C либо C++, вам должны быть известны три стандартных устройства STDIN, STDOUT и STDERR. Аналогичным образом, Java предоставляет следующие три стандартных потока:
- Стандартный ввод – используется для перевода данных в программу пользователя, клавиатура обычно используется в качестве стандартного потока ввода, представленного в виде System.in.
- Стандартный вывод – производится для вывода данных, полученных в программе пользователя, и обычно экран компьютера используется в качестве стандартного потока вывода, представленного в виде System.out.
- Стандартная ошибка – используется для вывода данных об ошибке, полученной в программе пользователя, чаще всего экран компьютера служит в качестве стандартного потока сообщений об ошибках, представленного в виде System.err.
Ниже представлена простая программа, которая создает InputStreamReader для чтения стандартного потока ввода, до введения пользователем «q»:
Пример
Разместим представленный выше код в файле ReadConsole.java и попробуем скомпилировать и выполнить его согласно тому, как это представлено в следующей программе. Данная программа продолжает чтение и вывод одного и того же символа до нажатия ‘q’:
Чтение и запись файла
Как было указано выше, поток представляет собой последовательность данных. InputStream используется для считывания данных с источника, OutputStream служит для записи данных по месту назначения.
Ниже представлена иерархия классов для управления потоками Ввода и Вывода.

В данном уроке нам предстоит рассмотреть два важных потока: FileInputStream и FileOutputStream.
Поток FileInputStream – чтение из файла
Поток FileInputStream – это поток, который используется в Java для чтения данных из файла. Объекты могут быть созданы при использовании ключевого слова new, доступны несколько типов конструкторов.
Представленный конструктор использует имя файла в качестве потока с целью создания объекта входного потока для считывания файла:
Представленный ниже конструктор использует объектный файл с целью создания объекта входного потока для чтения файла. Сперва мы создаем объектный файл при использовании метода File() следующим образом:
Теперь, получив объект InputStream, следует ознакомиться со следующим перечнем вспомогательных методов, которые могут быть использованы для считывания потока либо выполнения иных операций в потоке.
| № | Метод и описание |
| 1 | public void close() throws IOException<> Данный метод в Java закрывает выходной файловый поток. Освобождает какие-либо системные ресурсы, связанные с файлом. Выдает IOException. |
| 2 | protected void finalize()throws IOException <> Данный метод выполняет очистку соединения с файлом. Позволяет удостовериться в вызове закрытого метода данного выходного файлового потока при отсутствии каких-либо ссылок на данный поток. Выдает IOException. |
| 3 | public int read(int r)throws IOException<> Данный метод осуществляет в Java считывание заданных байтов данных из InputStream. Возврат данных типа int. Возврат следующего байта данных, в конце файла будет произведен возврат к -1. |
| 4 | public int read(byte[] r) throws IOException<> Данный метод производит считывание байтов r.length из входного потока в массив. Возврат общего числа считанных байтов. В конце файла будет произведен возврат к -1. |
| 5 | public int available() throws IOException<> Выдает число байтов, которые могут быть считаны из входного файлового потока. Возврат данных типа int. |
Существуют также другие доступные входные потоки, более детальные сведения о которых представлены по следующим ссылкам:
Поток FileOutputStream – создание и запись файла
Поток FileOutputStream – это поток, который используется в Java для создания файла и последующей записи в него. Поток создаст файл в случае его отсутствия перед его открытием для вывода.
Далее представлены два конструктора, которые могут быть задействованы при создании объекта FileOutputStream.
Представленный конструктор использует имя файла в качестве строки с целью создания объекта входного потока для записи файла в Java:
Представленный ниже конструктор использует объектный файл с целью создания объекта выходного потока для записи файла. Сперва мы создаем объектный файл при использовании метода File() следующим образом:
Теперь, получив объект OutputStream, следует ознакомиться со следующим перечнем вспомогательных методов, которые могут быть использованы для записи потока либо выполнения иных операций в потоке.
| № | Метод и описание |
| 1 | public void close() throws IOException<> Данный метод в Java закрывает выходной файловый поток. Освобождает какие-либо системные ресурсы, связанные с файлом. Выдает IOException. |
| 2 | protected void finalize()throws IOException <> Данный метод выполняет очистку соединения с файлом. Позволяет удостовериться в вызове закрытого метода данного выходного файлового потока при отсутствии каких-либо ссылок на данный поток. Выдает IOException. |
| 3 | public void write(int w)throws IOException<> Данный метод осуществляет запись заданного байта в выходной поток. |
| 4 | public void write(byte[] w) Запись байтов w.length из указанного массива байтов в OutputStream. |
Существуют также другие доступные выходные потоки, более детальные сведения о которых представлены по следующим ссылкам:
Пример
В следующем примере представлены InputStream и OutputStream – потоки для чтения, создания и записи файла:
Представленный выше java-код создаст файл file.txt и пропишет заданные символы в формате char. То же самое будет выводиться на экран стандартного вывода.
Навигация по файловой системе и вводу/выводу
Существует ряд других классов, которые нам предстоит рассмотреть с целью ознакомления с основами навигации в файловой системе и вводу/выводу.
Каталоги в Java
В Java каталог представлен Файлом, который может содержать список других файлов и каталогов. Используя объект File, вы можете создать каталог, прокрутить список файлов, представленных в каталоге. Для получения более детальных сведений, ознакомьтесь с перечнем всех методов, которые могут быть вызваны из объекта File, будучи связанными с каталогами.
Создание каталогов
Существуют два служебных метода File, которые могут быть использованы для создания каталогов:
- Метод mkdir() позволяет создать папку в Java, возвращая значение true при успехе операции, и false в случае сбоя. Сбой свидетельствует о том, что путь указанный в объекте File уже существует, либо что каталог не может быть создан в связи с тем, что полный путь еще не существует.
- Метод mkdirs() создает каталог и все вышестоящие каталоги.
В следующем примере представлено создание папки «/java/proglang/newdir»:
Пример
Скомпилируйте и выполните следующий код для создания каталога «/java/proglang/newdir».
Примечание ? Java автоматически формирует разделители пути в UNIX и Windows с учетом соглашений. При использовании косой черты (/) при работе с Java в системе Windows, производится корректное разрешение пути.
Список файлов в папке
Метод list(), представленный объектом File, может быть использован для предоставления перечня всех файлов и каталогов, имеющихся в заданной папке, в следующем виде:
Пример
Вследствие этого будет получен следующий результат, основанный на каталогах и файлах, доступных в вашем каталоге /NetBeans 8.2/Projects/ReadDirectory/ReadDirectory/:
Java – Файлы и ввод / вывод
Пакет java.io содержит почти все классы, которые вам могут понадобиться для ввода и вывода (ввода / вывода) в Java. Все эти потоки представляют собой источник ввода и назначение вывода. Поток в пакете java.io поддерживает много данных, таких как примитивы, объекты, локализованные символы и т. Д.
Поток
Поток может быть определен как последовательность данных. Есть два вида потоков –
InPutStream – InputStream используется для чтения данных из источника.
OutPutStream – OutputStream используется для записи данных в пункт назначения.
InPutStream – InputStream используется для чтения данных из источника.
OutPutStream – OutputStream используется для записи данных в пункт назначения.

Java обеспечивает мощную, но гибкую поддержку ввода / вывода, относящуюся к файлам и сетям, но в этом руководстве рассматриваются базовые функции, связанные с потоками и вводом / выводом. Мы увидим наиболее часто используемые примеры один за другим –
Байтовые потоки
Потоки байтов Java используются для ввода и вывода 8-битных байтов. Хотя существует много классов, связанных с потоками байтов, но наиболее часто используемые классы – FileInputStream и FileOutputStream . Ниже приведен пример, который использует эти два класса для копирования входного файла в выходной файл:
Теперь давайте получим файл input.txt со следующим содержимым –
В качестве следующего шага скомпилируйте вышеуказанную программу и выполните ее, что приведет к созданию файла output.txt с тем же содержимым, что и в input.txt. Итак, давайте поместим приведенный выше код в файл CopyFile.java и сделаем следующее:
Потоки персонажей
Потоки байтов Java используются для ввода и вывода 8-битных байтов, тогда как потоки символов Java используются для ввода и вывода 16-битных юникодов. Хотя есть много классов, связанных с символьными потоками, но наиболее часто используемые классы – FileReader и FileWriter . Хотя внутренне FileReader использует FileInputStream, а FileWriter использует FileOutputStream, но здесь основное отличие состоит в том, что FileReader читает два байта за раз, а FileWriter записывает два байта за раз.
Мы можем переписать приведенный выше пример, в котором эти два класса используются для копирования входного файла (содержащего символы Юникода) в выходной файл –
Теперь давайте получим файл input.txt со следующим содержимым –
В качестве следующего шага скомпилируйте вышеуказанную программу и выполните ее, что приведет к созданию файла output.txt с тем же содержимым, что и в input.txt. Итак, давайте поместим приведенный выше код в файл CopyFile.java и сделаем следующее:
Стандартные потоки
Все языки программирования обеспечивают поддержку стандартного ввода-вывода, когда программа пользователя может принимать ввод с клавиатуры, а затем выводить ее на экран компьютера. Если вы знакомы с языками программирования C или C ++, вы должны знать о трех стандартных устройствах STDIN, STDOUT и STDERR. Точно так же Java предоставляет следующие три стандартных потока:
Стандартный ввод – используется для подачи данных в пользовательскую программу, и обычно клавиатура используется в качестве стандартного потока ввода и представлена как System.in .
Стандартный вывод – используется для вывода данных, созданных программой пользователя, и обычно для стандартного потока вывода используется экран компьютера, представленный как System.out .
Стандартная ошибка – используется для вывода данных об ошибках, созданных программой пользователя, и обычно для стандартного потока ошибок используется экран компьютера, представленный как System.err .
Стандартный ввод – используется для подачи данных в пользовательскую программу, и обычно клавиатура используется в качестве стандартного потока ввода и представлена как System.in .
Стандартный вывод – используется для вывода данных, созданных программой пользователя, и обычно для стандартного потока вывода используется экран компьютера, представленный как System.out .
Стандартная ошибка – используется для вывода данных об ошибках, созданных программой пользователя, и обычно для стандартного потока ошибок используется экран компьютера, представленный как System.err .
Ниже приведена простая программа, которая создает InputStreamReader для чтения стандартного потока ввода, пока пользователь не введет «q» –
Давайте сохраним приведенный выше код в файле ReadConsole.java и попробуем скомпилировать и выполнить его, как показано в следующей программе. Эта программа продолжает читать и выводить один и тот же символ, пока мы не нажмем ‘q’ –
Чтение и запись файлов
Как описано ранее, поток может быть определен как последовательность данных. InputStream используется для чтения данных из источника, а OutputStream используется для записи данных в место назначения.
Вот иерархия классов для работы с потоками ввода и вывода.

Двумя важными потоками являются FileInputStream и FileOutputStream , которые будут обсуждаться в этом руководстве.
FileInputStream
Этот поток используется для чтения данных из файлов. Объекты могут быть созданы с помощью ключевого слова new, и существует несколько типов конструкторов.
Следующий конструктор принимает имя файла в виде строки для создания объекта входного потока для чтения файла –
Следующий конструктор принимает объект файла для создания объекта входного потока для чтения файла. Сначала мы создаем объект файла, используя метод File () следующим образом:
Когда у вас есть объект InputStream , появляется список вспомогательных методов, которые можно использовать для чтения в потоке или для выполнения других операций в потоке.
public void close () генерирует IOException <>
Этот метод закрывает поток вывода файла. Освобождает любые системные ресурсы, связанные с файлом. Выдает IOException.
Защищенный void finalize () выбрасывает IOException <>
Этот метод очищает соединение с файлом. Гарантирует, что метод close этого потока вывода файла вызывается, когда больше нет ссылок на этот поток. Выдает IOException.
public int read (int r) выдает IOException <>
Этот метод читает указанный байт данных из InputStream. Возвращает int. Возвращает следующий байт данных, и -1 будет возвращено, если это конец файла.
public int read (byte [] r) выдает IOException <>
Этот метод считывает байты r.length из входного потока в массив. Возвращает общее количество прочитанных байтов. Если это конец файла, -1 будет возвращено.
public int available () выдает IOException <>
Дает количество байтов, которые могут быть прочитаны из этого потока ввода файла. Возвращает int.
public void close () генерирует IOException <>
Этот метод закрывает поток вывода файла. Освобождает любые системные ресурсы, связанные с файлом. Выдает IOException.
Защищенный void finalize () выбрасывает IOException <>
Этот метод очищает соединение с файлом. Гарантирует, что метод close этого потока вывода файла вызывается, когда больше нет ссылок на этот поток. Выдает IOException.
public int read (int r) выдает IOException <>
Этот метод читает указанный байт данных из InputStream. Возвращает int. Возвращает следующий байт данных, и -1 будет возвращено, если это конец файла.
public int read (byte [] r) выдает IOException <>
Этот метод считывает байты r.length из входного потока в массив. Возвращает общее количество прочитанных байтов. Если это конец файла, -1 будет возвращено.
public int available () выдает IOException <>
Дает количество байтов, которые могут быть прочитаны из этого потока ввода файла. Возвращает int.
Доступны и другие важные входные потоки, более подробно вы можете обратиться к следующим ссылкам –
FileOutputStream
FileOutputStream используется для создания файла и записи в него данных. Поток создаст файл, если он еще не существует, прежде чем открыть его для вывода.
Вот два конструктора, которые можно использовать для создания объекта FileOutputStream.
Следующий конструктор принимает имя файла в виде строки для создания объекта входного потока для записи файла –
Следующий конструктор принимает объект файла для создания объекта потока вывода для записи файла. Сначала мы создаем объект файла с помощью метода File () следующим образом:
Если у вас есть объект OutputStream в руке, появляется список вспомогательных методов, которые можно использовать для записи в поток или для выполнения других операций в потоке.
public void close () генерирует IOException <>
Этот метод закрывает поток вывода файла. Освобождает любые системные ресурсы, связанные с файлом. Выдает IOException.
Защищенный void finalize () выбрасывает IOException <>
Этот метод очищает соединение с файлом. Гарантирует, что метод close этого потока вывода файла вызывается, когда больше нет ссылок на этот поток. Выдает IOException.
public void write (int w) выдает IOException <>
Этот метод записывает указанный байт в выходной поток.
public void write (byte [] w)
Записывает байты w.length из упомянутого байтового массива в OutputStream.
public void close () генерирует IOException <>
Этот метод закрывает поток вывода файла. Освобождает любые системные ресурсы, связанные с файлом. Выдает IOException.
Защищенный void finalize () выбрасывает IOException <>
Этот метод очищает соединение с файлом. Гарантирует, что метод close этого потока вывода файла вызывается, когда больше нет ссылок на этот поток. Выдает IOException.
public void write (int w) выдает IOException <>
Этот метод записывает указанный байт в выходной поток.
public void write (byte [] w)
Записывает байты w.length из упомянутого байтового массива в OutputStream.
Доступны и другие важные выходные потоки, более подробно вы можете обратиться к следующим ссылкам –
Ниже приведен пример для демонстрации InputStream и OutputStream:
Приведенный выше код создаст файл test.txt и запишет заданные числа в двоичном формате. То же самое будет вывод на экране стандартного вывода.
Навигация по файлам и ввод / вывод
Есть несколько других классов, которые мы пройдем, чтобы познакомиться с основами файловой навигации и ввода-вывода.
Каталоги на Java
Каталог – это файл, который может содержать список других файлов и каталогов. Вы используете объект File для создания каталогов, чтобы перечислить файлы, доступные в каталоге. Для получения полной информации, проверьте список всех методов, которые вы можете вызвать в объекте File, и что связано с каталогами.
Создание каталогов
Существует два полезных метода служебных файлов , которые можно использовать для создания каталогов:
Метод mkdir () создает каталог, возвращая true в случае успеха и false в случае ошибки. Ошибка указывает, что путь, указанный в объекте File, уже существует или что каталог не может быть создан, поскольку еще не существует полного пути.
Метод mkdirs () создает каталог и всех его родителей.
Метод mkdir () создает каталог, возвращая true в случае успеха и false в случае ошибки. Ошибка указывает, что путь, указанный в объекте File, уже существует или что каталог не может быть создан, поскольку еще не существует полного пути.
Метод mkdirs () создает каталог и всех его родителей.
Следующий пример создает каталог “/ tmp / user / java / bin” –
Скомпилируйте и выполните приведенный выше код для создания “/ tmp / user / java / bin”.
Примечание. Java автоматически позаботится о разделителях путей в UNIX и Windows в соответствии с соглашениями. Если вы используете косую черту (/) в версии Java для Windows, путь все равно будет корректным.
Каталоги листинга
Вы можете использовать метод list (), предоставленный объектом File, чтобы вывести список всех файлов и каталогов, доступных в каталоге, следующим образом:
Это даст следующий результат на основе каталогов и файлов, доступных в вашем каталоге / tmp –
Чтение и запись файлов
В Java есть четыре основных абстрактных класса, реализующих потоки ввода-вывода: InputStream, OutputStream, Reader, Writer. Первые два работают с байтами, вторые – с символами.
Для работы с файлами от этих абстрактных классов созданы соответственно классы FileInputStream, FileOutputStream, FileReader, FileWriter. Они являются адаптерами для объектов класса File к «интерфейсам» InputStream, OutputStream, Reader, Writer, т. е. к их методам.
Скажем несколько слов об адаптере как паттерне, или шаблоне, проектирования. Класс-адаптер A наследуется от интерфейса B, к которому приспосабливается объект другого класса – C. Класс-адаптер A имеет поле типа класса объекта C.
Например, объект File адаптируется к потоку ввода InputStream, т. е. все, что мы хотим получить из File, в конечном итоге мы будем получать из InputStream. Фактически мы работаем с InputStream, через адаптер FileInputStream, который с одной стороны наследуется от InputStream, а с другой – имеет поле, которому присваивается объект File.
Адаптер выполняет работу по получению данных из файла и адаптации их к тому виду, который можно передать в методы InputStream. Класс-адаптер, в данном примере – FileInputStream, переопределяет методы InputStream, добавляя в них свой код.
В основной ветке сначала создается объект, для которого требуется адаптер. Затем создается переменная класса, к которому выполняется адаптация. Этой переменной присваивается объект класса-адаптера, в конструктор которого передается адаптируемый объект.
Часто переменную определяют самим классом-адаптером:
В конструктор можно передать строку-адрес. Объект File будет создан внутри адаптера. Пример побайтового копирования файла:
Если используются относительные адреса, они должны начинаться от корня проекта.
В конструктор FileOutputStream можно также передать второй аргумент true. В этом случае, если файл существует, данные в него будут добавляться. Перезаписи файла не произойдет.
Метод available() объекта класса FileInputStream возвращает количество непрочитанных байтов. Метод read() читает один байт и расширяет его до типа int. Кроме этого, есть другой метод read(), читающий массив байт в переменную-аргумент и возвращающий количество реально прочитанных байт. Метод write() также позволяет записывать блоками.
При чтении конца файла блок может содержать меньше прочитанных байт, чем размерность массива. Поэтому write() позволяет указывать срез массива.
У объектов FileOutputStream имеется метод flush(), который принудительно записывает находящиеся в буфере байты на диск. При вызове close() это происходит автоматически.
С помощью класса PrintStream также можно создать поток вывода в файл. PrintStream является наследником FilterOutputStream, который в свою очередь наследник OutputStream как и FileOutputStream.
Функция printf() предназначена для форматированного вывода.
Заметим, переменная System.out является объектом типа PrintStream.
В работе с вводом-выводом также используется другой паттерн проектирования – обертка (wrapper), он же декоратор (decorator). Декоратор расширяет функциональность объекта, а не приспосабливает объект к какому-либо стороннему интерфейсу.
Поэтому класс-обертка наследуется от того же класса или интерфейса, что и оборачиваемый объект. В классе-обертке переопределяются методы оборачиваемого объекта. В методах обертки вызываются методы оборачиваемого класса и вводится дополнительная функциональность.
В основной ветке создается объект оборачиваемого класса, который передается в конструктор обертки. Внутри класса-обертки есть поле типа декорируемого класса. Этому полю присваивается переданный объект.
BufferedInputStream – класс-обертка для InputStream (наследует через FilterInputStream). В отличие от InputStream класс BufferedInputStream позволяет предварительно читать в буфер порции байт, что уменьшает количество обращений к файлу. Существует также BufferedOutputStream.
Конструктор класса BufferedInputStream принимает объект InputStream или его наследника.
Хотя данные считываются блоками, метод read() извлекает их по одному. Однако в данном случае он будет извлекать их из буфера.
С помощью классов FileReader и FileWriter выполняется ввод-вывод в текстовые файлы.
Метод ready() возвращает истину, если остались непрочитанные символы.
Читать и писать можно блоками. Также методу write() можно передать строку:
Рассматривая ввод данных с клавиатуры, мы уже использовали класс BufferedReader, который наследуется от Reader и позволяет читать отдельные строки методом readLine(). Его также можно использовать для построчного чтения файлов: