Java вывести в файл
Чтобы работать с файлами, есть шикарный утилитный класс — java.nio.file.Files . У него есть методы просто на все случаи жизни. Все методы этого класса статические и работают с объектами типа Path. Методов очень много, поэтому мы рассмотрим только основные:
Метод | Описание |
---|---|
Создает новый файл с путем path | |
Создает новую директорию | |
Создает несколько директорий | |
Создает временный файл | |
Создает временную директорию | |
Удаляет файл или директорию, если она пуста | |
Копирует файл | |
Перемещает файл | |
Проверяет, что путь — это директория, а не файл | |
Проверяет, что путь — это файл, а не директория | |
Проверяет, что объект по заданному пути существует | |
Возвращает размер файла | |
Возвращает все содержимое файла в виде массива байт | |
Возвращает все содержимое файла в виде строки | |
Возвращает все содержимое файла в виде списка строк | |
Записывает в файл массив байт | |
Записывает в файл строку | |
Возвращает коллекцию файлов (и поддиректорий) из заданной директории |
Класс BufferedInputStream
Думаю, учитывая знания из прошлых лекций, ты легко сможешь сказать, зачем нужен класс BufferedInputStream и какие преимущества у него есть по сравнению с FileInputStream :) Мы уже встречались с буферизированными потоками, поэтому попробуй предположить (или вспомнить), прежде чем продолжить чтение :) Буферизированные потоки нужны прежде всего для оптимизации ввода-вывода. Обращение к источнику данных, например, чтение из файла, — дорогостоящая в плане производительности операция. И каждый раз обращаться к файлу для чтения по одному байту расточительно. Поэтому BufferedInputStream считывает данные не по одному байту, а блоками и временно хранит их в специальном буфере. Это позволяет нам оптимизировать работу программы за счет того, что мы уменьшаем количество обращений к файлу. Давай посмотрим, как это выглядит: Здесь мы создали объект BufferedInputStream . Он принимает на вход объект InputStream или любого его наследника, так что предыдущий FileInputStream подойдет. В качестве дополнительного параметра он принимает размер буфера в байтах. Теперь благодаря этому данные будут считываться из файла не по одному байту, а по 200! Представь, насколько мы сократили количество обращений к файлу. Для сравнения производительности ты можешь взять какой-нибудь большой текстовый файл размером несколько мегабайт и сравнить, сколько займет его чтение и вывод в консоль в миллисекундах с использованием FileInputStream и BufferedInputStream . Вот оба варианта кода для примера: При чтении файла размером 1,5 Мб на моем компьютере FileInputStream выполнил работу за ~3500 миллисекунд, а вот BufferedInputStream — за ~1700 миллисекунд. Как видишь, буферизированный поток оптимизировал работу программы в 2 раза! :) Мы еще продолжим изучать классы ввода-вывода — до встречи!
Класс FileOutputStream
Главное назначение класса FileOutputStream — запись байтов в файл. Ничего сложного :) FileOutputStream является одной из реализаций абстрактного класса OutputStream . В конструкторе объекты этого класса принимают либо путь к целевому файлу (в который и нужно записать байты), либо объект класса File . Рассмотрим оба примера: При создании объекта File мы указали в конструкторе путь, где он должен будет находиться. Создавать его заранее нет необходимости: если он не существует, программа создаст его сама. Можно обойтись и без создания лишнего объекта, и просто передать строку с адресом: Результат в обоих случаях будет одинаковым. Мы можем открыть наш файл и увидеть там: Однако есть здесь один нюанс. Попробуй запустить код из примера выше несколько раз подряд, а потом загляни в файл, и ответь на вопрос: сколько записанных в него строк ты видишь? Всего одну. Но ведь ты запускал код несколько раз. Однако при этом данные, оказывается, всякий раз перезаписывались, заменяя старые. Что делать, если нас это не устраивает, и требуется последовательная запись? Что если мы хотим записать наше приветствие в файл три раза подряд? Здесь все просто. Поскольку сам язык не может знать, какое именно поведение нам нужно в каждом случае, в конструктор FileOutputStream ты можешь передать дополнительный параметр — boolean append . Если его значение true, данные будут дозаписаны в конец файла. Если false (а по умолчанию это значение и есть false), старые данные будут стерты, а новые записаны. Давай проверим и запустим наш измененный код трижды: Результат в файле: Другое дело! Не забывай об этой особенности при использовании классов ввода-вывода. В свое время и мне приходилось часами сидеть над задачами, чтобы понять, куда деваются из файлов мои старые данные :) Ну и конечно, как и в случае с другими классами I/O, не забываем об освобождении ресурсов через метод close() .
Класс FileInputStream
У класса FileInputStream назначение противоположное — чтение байтов из файла. Так же как FileOutputStream наследует OutputStream , этот класс происходит от абстрактного класса InputStream . Запишем в наш текстовый « test.txt » несколько строк текста: Вот как будет выглядеть реализация чтения данных из файла при помощи FileInputStream : Мы считываем из файла по одному байту, преобразуем считанные байты в символы и выводим их в консоль. А вот и результат в консоли:
3. Копирование, перемещение и удаление
Копировать, перемещать и удалять файлы так же легко. На директории это тоже распространяется, но они должны быть пустые.
Код | Примечание |
---|---|
Копирует файл | |
Перемещает и переименовывает файл | |
Удаляет файл |
Запись файлов и класс FileOutputStream
Класс FileOutputStream предназначен для записи байтов в файл. Он является производным от класса OutputStream, поэтому наследует всю его функциональность.
Через конструктор класса FileOutputStream задается файл, в который производится запись. Класс поддерживает несколько конструкторов:
Файл задается либо через строковый путь, либо через объект File. Второй параметр - append задает способ записи: eсли он равен true, то данные дозаписываются в конец файла, а при false - файл полностью перезаписывается
Например, запишем в файл строку:
Для создания объекта FileOutputStream используется конструктор, принимающий в качестве параметра путь к файлу для записи. Если такого файла нет, то он автоматически создается при записи. Так как здесь записываем строку, то ее надо сначала перевести в массив байтов. И с помощью метода write строка записывается в файл.
Для автоматического закрытия файла и освобождения ресурса объект FileOutputStream создается с помощью конструктции try. catch.
При этом необязательно записывать весь массив байтов. Используя перегрузку метода write() , можно записать и одиночный байт:
Чтение файлов. Класс FileReader
Класс FileReader наследуется от абстрактного класса Reader и предоставляет функциональность для чтения текстовых файлов.
Для создания объекта FileReader мы можем использовать один из его конструкторов:
А используя методы, определенные в базом классе Reader, произвести чтение файла:
Также мы можем считывать в промежуточный буфер из массива символов:
В данном случае считываем последовательно символы из файла в массив из 256 символов, пока не дойдем до конца файла в этом случае метод read возвратит число -1.
Поскольку считанная порция файла может быть меньше 256 символов (например, в файле всего 73 символа), и если количество считанных данных меньше размера буфера (256), то выполняем копирование массива с помощью метода Arrays.copy. То есть фактически обрезаем массив buf, оставляя в нем только те символы, которые считаны из файла.
2. Создание файлов и директорий
Файлы и директории создавать очень просто. Убедимся на примерах:
Код | Примечание |
---|---|
Создает файл | |
Создает директорию | |
Создает директорию и все нужные поддиректории, если их не существует. |
5. Работа с содержимым файла
И наконец, есть целая серия методов, которые позволяют легко прочитать или записать содержимое файла. Пример:
Хотя с помощью ранее рассмотренных классов можно записывать текст в файлы, однако они предназначены прежде всего дл работы с бинарными потоками данных, и их возможностей для полноценной работы с текстовыми файлами недостаточно. И для этой цели служат совсем другие классы, которые являются наследниками абстрактных классов Reader и Writer .
Потоки байтов
Класс InputStream
Класс InputStream является базовым для всех классов, управляющих байтовыми потоками ввода. Рассмотрим его основные методы:
int available() : возвращает количество байтов, доступных для чтения в потоке
void close() : закрывает поток
int read() : возвращает целочисленное представление следующего байта в потоке. Когда в потоке не останется доступных для чтения байтов, данный метод возвратит число -1
int read(byte[] buffer) : считывает байты из потока в массив buffer. После чтения возвращает число считанных байтов. Если ни одного байта не было считано, то возвращается число -1
int read(byte[] buffer, int offset, int length) : считывает некоторое количество байтов, равное length, из потока в массив buffer. При этом считанные байты помещаются в массиве, начиная со смещения offset, то есть с элемента buffer[offset] . Метод возвращает число успешно прочитанных байтов.
long skip(long number) : пропускает в потоке при чтении некоторое количество байт, которое равно number
Класс OutputStream
Класс OutputStream является базовым классом для всех классов, которые работают с бинарными потоками записи. Свою функциональность он реализует через следующие методы:
void close() : закрывает поток
void flush() : очищает буфер вывода, записывая все его содержимое
void write(int b) : записывает в выходной поток один байт, который представлен целочисленным параметром b
void write(byte[] buffer) : записывает в выходной поток массив байтов buffer.
void write(byte[] buffer, int offset, int length) : записывает в выходной поток некоторое число байтов, равное length , из массива buffer , начиная со смещения offset , то есть с элемента buffer[offset] .
Запись файлов. Класс FileWriter
Класс FileWriter является производным от класса Writer. Он используется для записи текстовых файлов.
Чтобы создать объект FileWriter, можно использовать один из следующих конструкторов:
Так, в конструктор передается либо путь к файлу в виде строки, либо объект File, который ссылается на конкретный текстовый файл. Параметр append указывает, должны ли данные дозаписываться в конец файла (если параметр равен true), либо файл должен перезаписываться.
Запишем в файл какой-нибудь текст:
В конструкторе использовался параметр append со значением false - то есть файл будет перезаписываться. Затем с помощью методов, определенных в базовом классе Writer производится запись данных.
Абстрактные классы Reader и Writer
Абстрактный класс Reader предоставляет функционал для чтения текстовой информации. Рассмотрим его основные методы:
absract void close() : закрывает поток ввода
int read() : возвращает целочисленное представление следующего символа в потоке. Если таких символов нет, и достигнут конец файла, то возвращается число -1
int read(char[] buffer) : считывает в массив buffer из потока символы, количество которых равно длине массива buffer. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
int read(CharBuffer buffer) : считывает в объект CharBuffer из потока символы. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
absract int read(char[] buffer, int offset, int count) : считывает в массив buffer, начиная со смещения offset, из потока символы, количество которых равно count
long skip(long count) : пропускает количество символов, равное count. Возвращает число успешно пропущенных символов
Класс Writer определяет функционал для всех символьных потоков вывода. Его основные методы:
Writer append(char c) : добавляет в конец выходного потока символ c. Возвращает объект Writer
Writer append(CharSequence chars) : добавляет в конец выходного потока набор символов chars. Возвращает объект Writer
abstract void close() : закрывает поток
abstract void flush() : очищает буферы потока
void write(int c) : записывает в поток один символ, который имеет целочисленное представление
void write(char[] buffer) : записывает в поток массив символов
absract void write(char[] buffer, int off, int len) : записывает в поток только несколько символов из массива buffer. Причем количество символов равно len, а отбор символов из массива начинается с индекса off
void write(String str) : записывает в поток строку
void write(String str, int off, int len) : записывает в поток из строки некоторое количество символов, которое равно len, причем отбор символов из строки начинается с индекса off
Функционал, описанный классами Reader и Writer, наследуется непосредственно классами символьных потоков, в частности классами FileReader и FileWriter соответственно, предназначенными для работы с текстовыми файлами.
Привет! В сегодняшней лекции продолжим разговор о потоках ввода и вывода в Java, или сокращенно — Java I/O («input-output»). Это не первая лекция на данную тему, и далеко не последняя :) Так уж получилось, что Java как язык предоставляет много возможностей по работе с вводом-выводом. Классов, которые реализуют эту функциональность довольно много, поэтому мы разделили их на несколько лекций, чтобы ты поначалу не запутался :) В прошлых лекциях мы коснулись BufferedReader ’a, а также абстрактных классов InputStream & OutputStream и нескольких наследников. Сегодня рассмотрим 3 новых класса: FileInputStream , FileOutputStream и BufferedInputStream .
4. Проверка типа файла и факта существования
Когда у вас есть какой-то путь, полученный извне, вы бы хотели знать, это файл или директория. Ну и вообще: существует такой файл/директория или нет?
Для этого тоже есть специальные методы. Так же можно легко узнать длину файла:
Код | Примечание |
---|
Чтение файлов и класс FileInputStream
Для считывания данных из файла предназначен класс FileInputStream , который является наследником класса InputStream и поэтому реализует все его методы.
Для создания объекта FileInputStream мы можем использовать ряд конструкторов. Наиболее используемая версия конструктора в качестве параметра принимает путь к считываемому файлу:
Если файл не может быть открыт, например, по указанному пути такого файла не существует, то генерируется исключение FileNotFoundException .
Считаем данные из ранее записанного файла и выведем на консоль:
В данном случае мы считываем каждый отдельный байт в переменную i:
Когда в потоке больше нет данных для чтения, метод возвращает число -1.
Затем каждый считанный байт конвертируется в объект типа char и выводится на консоль.
Подобным образом можно считать данные в массив байтов и затем производить с ним манипуляции:
Совместим оба класса и выполним чтение из одного и запись в другой файл:
Классы FileInputStream и FileOutputStream предназначены прежде всего для записи двоичных файлов, то есть для записи и чтения байтов. И хотя они также могут использоваться для работы с текстовыми файлами, но все же для этой задачи больше подходят другие классы.
Отличительной чертой многих языков программирования является работа с файлами и потоками. В Java основной функционал работы с потоками сосредоточен в классах из пакета java.io .
Ключевым понятием здесь является понятие потока . Хотя понятие "поток" в программировании довольно перегружено и может обозначать множество различных концепций. В данном случае применительно к работе с файлами и вводом-выводом мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т.д.).
Объект, из которого можно считать данные, называется потоком ввода , а объект, в который можно записывать данные, - потоком вывода . Например, если надо считать содержание файла, то применяется поток ввода, а если надо записать в файл - то поток вывода.
В основе всех классов, управляющих потоками байтов, находятся два абстрактных класса: InputStream (представляющий потоки ввода) и OutputStream (представляющий потоки вывода)
Но поскольку работать с байтами не очень удобно, то для работы с потоками символов были добавлены абстрактные классы Reader (для чтения потоков символов) и Writer (для записи потоков символов).
Все остальные классы, работающие с потоками, являются наследниками этих абстрактных классов. Основные классы потоков:
Читайте также: