Как записать в файл с arraylist на джава
В этом уроке мы будем читать и записывать файлы на Java с помощью FileReader, FileWriter, BufferedReader, BufferedWriter, FileInputStream, FileOutputStream и т. Д.
Вступление
В этой статье мы погрузимся в Чтение и запись файлов на Java .
При программировании, независимо от того, создаете ли вы мобильное приложение, веб-приложение или просто пишете сценарии, вам часто приходится читать или записывать данные в файл. Эти данные могут быть данными кэша, данными, которые вы получили для набора данных, изображения или практически всем, что вы можете придумать.
В этом уроке мы покажем наиболее распространенные способы чтения и записи файлов на Java.
Java предоставляет несколько API (также известных как Java I/O ) для чтения и записи файлов с момента ее первых выпусков. В последующих выпусках ввод-вывод Java был улучшен, упрощен и расширен для поддержки новых функций.
Прежде чем мы перейдем к некоторым реальным примерам, это поможет понять доступные вам классы, которые будут обрабатывать чтение и запись данных в файлы. В следующих разделах мы дадим краткий обзор классов ввода-вывода Java и объясним, что они делают, затем мы рассмотрим потоки Java NIO и, наконец, покажем некоторые примеры чтения и записи данных в файлы.
Потоки ввода-вывода
Существует два типа потоков, которые вы можете использовать для взаимодействия с файлами:
Для каждого из вышеперечисленных типов потоков существует несколько вспомогательных классов, поставляемых с Java, которые мы кратко рассмотрим ниже.
Потоки символов
Потоки символов используются для чтения или записи типа данных символов. Давайте рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io посылка.
Вот некоторые классы, которые вы должны знать, которые можно использовать для чтения символьных данных:
-
: Абстрактный класс для чтения потока символов. : Класс, используемый для чтения потока байтов и преобразования в поток символов. : Класс для чтения символов из файла. : Это оболочка над классом Reader , которая поддерживает возможности буферизации. Во многих случаях это наиболее предпочтительный класс для чтения данных, поскольку из файла можно прочитать больше данных за один вызов read () , что уменьшает количество фактических операций ввода-вывода с файловой системой.
И вот некоторые классы, которые вы можете использовать для записи символьных данных в файл:
-
: Это абстрактный класс для записи потоков символов. : Этот класс используется для записи потоков символов, а также для преобразования их в потоки байтов. : Класс для фактической записи символов в файл. : Это оболочка над классом Writer , которая также поддерживает возможности буферизации. Это наиболее предпочтительный класс для записи данных в файл, так как в файл может быть записано больше данных за один вызов write () . И , как и BufferedReader , это уменьшает общее количество операций ввода-вывода с файловой системой.
Потоки байтов
Потоки байтов используются для чтения или записи байтовых данных с файлами. Это отличается от того, как они обрабатывали данные раньше. Здесь вы работаете с необработанными байтами, которые могут быть символами, данными изображений, данными в юникоде (для представления символа требуется 2 байта) и т. Д.
В этом разделе мы рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io посылка.
Вот классы, используемые для чтения байтовых данных:
-
: Абстрактный класс для чтения потоков байтов. : Класс для простого считывания байтов из файла. : Это оболочка над InputStream , которая поддерживает возможности буферизации. Как мы видели в потоках символов, это более эффективный метод, чем FileInputStream .
А вот классы, используемые для записи байтовых данных:
-
: Абстрактный класс для записи байтовых потоков. : Класс для записи необработанных байтов в файл. : Этот класс является оболочкой над OutputStream для поддержки возможностей буферизации. И опять же, как мы видели в потоках символов, это более эффективный метод, чем FileOutputStream благодаря буферизации.
Потоки Java NIO
Java NIO -это неблокирующий API ввода-вывода, который был представлен еще в Java 4 и может быть найден в пакете/| java.nio . С точки зрения производительности это большое улучшение API для операций ввода-вывода.
Буферы, селекторы и каналы являются тремя основными компонентами Java NIO, хотя в этой статье мы сосредоточимся исключительно на использовании классов NIO для взаимодействия с файлами, а не обязательно на концепциях, лежащих в основе API.
Поскольку этот учебник посвящен чтению и записи файлов, в этом коротком разделе мы обсудим только связанные классы:
-
: Это иерархическая структура фактического расположения файла и обычно используется для поиска файла, с которым вы хотите взаимодействовать. : Это класс, который предоставляет несколько служебных методов для создания Пути из заданного URI строки. : Это еще один служебный класс, который имеет несколько методов для чтения и записи файлов, не блокируя выполнение в потоках.
Используя эти несколько классов, вы можете легко взаимодействовать с файлами более эффективным способом.
Разница между вводом-выводом Java и NIO
Основное различие между этими двумя пакетами заключается в том, что методы read() и write() блокируют вызовы области ввода-вывода Java. Под этим мы подразумеваем, что поток, вызывающий один из этих методов, будет заблокирован до тех пор, пока данные не будут прочитаны или записаны в файл.
С другой стороны, в случае NIO методы не являются блокирующими. Это означает, что вызывающие потоки могут выполнять другие задачи (например, чтение/запись данных из другого источника или обновление пользовательского интерфейса), в то время как методы чтение или запись ожидают завершения своей операции. Это может привести к значительному повышению производительности, если вы имеете дело с большим количеством запросов ввода-вывода или большим количеством данных.
Примеры чтения и записи текстовых файлов
В предыдущих разделах мы обсуждали различные API, предоставляемые Java, и теперь пришло время использовать эти классы API в некотором коде.
Приведенный ниже пример кода обрабатывает чтение и запись текстовых файлов с использованием различных классов, которые мы подробно описали выше. Чтобы упростить вещи и обеспечить лучшее сравнение используемых фактических методов, входные и выходные данные будут оставаться одинаковыми между примерами.
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Примечание : Чтобы избежать путаницы в пути к файлу, пример кода будет считываться и записываться из файла в домашнем каталоге пользователя. Домашний каталог пользователя можно найти с помощью System.getProperty("user.home"); , который мы используем в наших примерах.
Чтение и запись с помощью программы чтения файлов и пишущей машинки
Давайте начнем с использования классов FileReader и Пишущая машинка :
Оба класса принимают строку, представляющую путь к файлу в их конструкторах. Вы также можете передать Файл объект, а также Файловый дескриптор .
Метод read() считывает и возвращает символ за символом, позволяя нам, например, использовать считанные данные в цикле while .
Не забудьте закрыть оба этих класса после использования!
Чтение и запись с помощью BufferedReader и BufferedWriter
Использование BufferedReader и BufferedWriter классов:
Чтение и запись с помощью FileInputStream и FileOutputStream
Использование FileInputStream и FileOutputStream классов:
Чтение и запись с помощью BufferedInputStream и BufferedOutputStream
Использование BufferedInputStream и BufferedOutputStream классов:
Чтение и запись с помощью классов Java.nio
Использование классов java.nio :
В случае , если вы заинтересованы в использовании потоков с java.nio , вы также можете использовать приведенные ниже методы, предоставляемые классом Files , которые работают так же, как потоки, которые мы рассмотрели ранее в статье:
Вывод
В этой статье мы рассмотрели наиболее распространенные способы чтения и записи данных в файл с использованием как пакета ввода-вывода Java, так и более нового пакета Java NIO. Всякий раз, когда это возможно, мы рекомендуем использовать классы Java NIO для файловых операций из-за его неблокирующего API, и, кроме того, код немного более удобен для обслуживания и чтения.
пример использования try-with-resources шаблон рекомендуется в руководстве API. Это гарантирует, что независимо от обстоятельств поток будет закрыт.
в Java 8, вы можете сделать это
который будет печатать все файлы в папке, исключая все каталоги. Если вам нужен список, выполните следующие действия:
если вы хотите вернуть List<File> вместо List<Path> просто карта это:
вы также должны убедиться, чтобы закрыть поток! В противном случае вы можете столкнуться с исключением, сообщающим вам, что слишком много файлов открыты. Читать здесь для получения дополнительной информации.
все ответы на этот вопрос, которые используют новые функции Java 8, пренебрегают закрытием потока. Примером в принятом ответе должно быть:
из javadoc Files.walk способ:
возвращаемый поток инкапсулирует один или несколько DirectoryStreams. Если своевременное избавление ресурсов файловой системы необходимо, конструкция try-with-resources должна использоваться для обеспечения метод close stream вызывается после потоковые операции завершены.
просто пройдите через все файлы, используя Files.walkFileTree (Java 7)
вы также можете создать фильтр, который затем может быть передан в newDirectoryStream способ выше
Если вы хотите больше опций, вы можете использовать эту функцию, которая направлена на заполнение arraylist файлов, присутствующих в папке. Варианты : recursivility и шаблон, чтобы соответствовать.
Я думаю, что это хороший способ прочитать все файлы в папке и подпапке
простой пример, который работает с Java 1.7 рекурсивно список файлов в каталогах, указанных в командной строке:
хотя я согласен с Ричем, Орианом и остальными для использования:
почему-то все примеры здесь используется абсолютное путь (т. е. полностью от корня или, скажем, буквы диска (C:\) для windows..)
Я хотел бы добавить, что можно использовать относительные путь-хорошо. Итак, если вы pwd (текущий каталог / папка) является folder1, и вы хотите разобрать folder1 / subfolder, вы просто пишете (в коде выше вместо ):
вот безопасное решение, хотя и не такое элегантное, как Java 8 Files.walk(..) :
список файлов из тестовой папки в пути к классу
вы можете фильтровать любые текстовые файлы или любое другое расширение ..просто замените его .MP3
чтобы расширить принятый ответ, я сохраняю имена файлов в ArrayList (вместо того, чтобы просто сбрасывать их в систему.из.println) я создал вспомогательный класс "MyFileUtils", чтобы он мог быть импортирован другими проектами:
я добавил полный путь к имени файла. Вы бы использовали его так:
ArrayList передается "value", но значение используется для указания на тот же объект ArrayList, живущий в куче JVM. Таким образом, каждый вызов рекурсии добавляет имена файлов в тот же ArrayList (мы не создаем новый ArrayList при каждом рекурсивном вызове).
Теперь, чтобы получить файлы из определенной папки, предположим, у вас есть папка с именем "res" в папке ресурсов, просто замените:
Если вы хотите иметь доступ в ваш com.пакет "название" тут:
Это будет читать указанные файлы расширения файла в заданном пути (также выглядит вложенные папки)
В этом уроке мы обсудим различные способы чтения файла в ArrayList .
Существует множество способов чтения файла в Java . Прочитав файл, мы можем выполнить множество операций с его содержимым.
Некоторые из этих операций, например сортировка, могут потребовать обработки всего содержимого файла в память. Для выполнения таких операций нам может понадобиться прочитать файл как Массив или Список строк или слов.
2. Использование FileReader
Существует несколько конструкторов, доступных для инициализации считывателя файлов :
Все эти конструкторы предполагают, что кодировка символов по умолчанию и размер байтового буфера по умолчанию являются подходящими.
Однако, если мы хотим предоставить пользовательскую кодировку символов и размер байтового буфера, мы можем использовать InputStreamReader или FileInputStream .
В следующем коде мы продемонстрируем, как читать строки из файла в ArrayList, используя FileReader:
3. Использование BufferedReader
Хотя FileReader довольно прост в использовании, рекомендуется всегда оборачивать его с помощью BuffereReader при чтении файла.
Это происходит потому, что BufferedReader использует буфер char для одновременного считывания нескольких значений из потока ввода символов и, следовательно, уменьшает количество вызовов read () , выполняемых базовым FileStream .
Конструкторы для BufferedReader принимают Reader в качестве входных данных. Кроме того, мы также можем указать размер буфера в конструкторах, но для большинства случаев использования размер по умолчанию достаточно велик:
В дополнение к унаследованным методам от класса Reader , BufferedReader также предоставляет метод readLine() для чтения всей строки как строки :
4. Использование Сканера
Еще один распространенный способ чтения файлов-через Scanner .
Сканер это простой текстовый сканер, используемый для разбора примитивных типов и строк с использованием регулярных выражений.
При чтении файлов/| Scanner инициализируется с помощью объектов File или FileReader :
Подобно BufferedReader, Scanner предоставляет readLine() метод для чтения всей строки . Дополнительно , он также предоставляет метод hasNext () , чтобы указать, доступно ли больше значений для чтения или нет:
Scanner разбивает свои входные данные на токены с помощью разделителя, разделителем по умолчанию является пробел. Эти токены могут быть преобразованы в значения различных типов с помощью различных доступных методов next ( nextInt , nextLong и т. Д.):
5. Использование Files.ReadAllLines
Этот метод также может принимать параметр charset для чтения в соответствии с определенной кодировкой символов:
6. Заключение
Подводя итог, мы обсудили некоторые распространенные способы чтения содержимого файла в ArrayList . Кроме того, мы рассмотрели некоторые преимущества и недостатки различных методов.
Существует множество способов чтения и записи файлов на Java .
Обычно у нас есть некоторые данные в памяти, с которыми мы выполняем операции, а затем сохраняем их в файле. Однако, если мы хотим изменить эту информацию, нам нужно поместить содержимое файла обратно в память и выполнить операции.
Этого можно достичь с помощью нескольких различных подходов:
- Файлы.Строки для чтения()
- Устройство для чтения файлов
- Сканер
- Буферизатор
- Поток ввода объекта
- API потоков Java
Файлы.Строки для чтения()
Начиная с Java 7, можно очень простым способом загрузить все строки файла в ArrayList :
Мы также можем указать кодировку для обработки различных форматов текста, если это необходимо:
Files.ReadAllLines() автоматически открывает и закрывает необходимые ресурсы.
Сканер
Каким бы приятным и простым ни был предыдущий метод, он полезен только для чтения файла строка за строкой. Что произойдет, если все данные будут храниться в одной строке?
Простым примером того, когда мы предпочли бы использовать Сканер , было бы, если бы в нашем файле была только одна строка, и данные должны быть проанализированы во что-то полезное.
Давайте взглянем на пример файла:
Запуск этого фрагмента кода приведет к тому, что мы получим ArrayList с этими элементами:
С другой стороны, если бы мы использовали только разделитель по умолчанию (пробел), то ArrayList выглядел бы так:
Сканер имеет некоторые полезные функции для анализа данных, такие как nextInt() , nextDouble () и т.д.
Даже если мы не видим этого, когда мы вызываем такие функции, как scanner.nextInt() или scanner.hasNextDouble () , Сканер использует регулярные выражения в фоновом режиме.
Очень важно: | Чрезвычайно Распространенная ошибка при использовании Сканера возникает при работе с файлами, содержащими несколько строк , и использовании . nextLine () в сочетании с . nextInt () , nextDouble () и т. Д.
Давайте взглянем на другой файл:
Часто новые разработчики, использующие Сканер , пишут код, подобный:
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Если вы начнете отладку и распечатаете отсканированное, вы увидите, что в хорошо загружено, но Строки пусты.
Почему это так? Первое, что важно отметить, это то, что как только Сканер считывает что-либо из файла, он продолжает сканирование файла с первого символа после ранее отсканированных данных.
Наш файл, на самом деле, выглядит так:
Когда мы впервые вызываем .nextInt() , Сканер считывает только число 12 и оставляет первое \n непрочитанным.
Поэтому, когда мы вызываем .nextLine () , в результате мы получаем пустую строку, так как Сканер не добавляет символ \n в возвращаемую строку.
Теперь Сканер находится в начале второй строки вашего файла, и когда мы пытаемся вызвать .nextInt() , Сканер обнаруживает что-то, что не может быть проанализировано в int и выдает вышеупомянутое Исключение InputMismatchException .
Решения
- Учитывая, что мы знаем, как example.txt отформатирован, мы можем прочитать весь файл строка за строкой и проанализировать необходимые строки с помощью Integer.parseInt() :
Буферизатор
BufferedReader считывает текст из потока ввода символов, но делает это путем буферизации символов для обеспечения эффективных операций .read () . Поскольку доступ к жесткому диску занимает очень много времени, BufferedReader собирает больше данных, чем мы просим, и сохраняет их в буфере.
Это подводит нас к тому, что BufferedReader хорошо подходит для чтения больших файлов. BufferedReader имеет значительно большую буферную память, чем Сканер (8192 символа по умолчанию против 1024 символов по умолчанию соответственно).
BufferedReader используется в качестве оболочки для других Читателей , и поэтому конструкторы для BufferedReader принимают Читатель объект в качестве параметра, например Читатель файлов .
Мы используем пробные ресурсы, поэтому нам не нужно закрывать считыватель вручную:
Рекомендуется обернуть файловый редактор с Буферным читателем , именно из-за преимуществ производительности.
Поток ввода объекта
ObjectInputStream следует использовать только вместе с ObjectOutputStream . Что эти два класса помогают нам сделать, так это сохранить объект (или массив объектов) в файл, а затем легко прочитать из этого файла.
Это можно сделать только с классами, реализующими Сериализуемый интерфейс. Интерфейс Сериализуемый не имеет методов или полей и служит только для определения семантики сериализуемости:
API потоков Java
Начиная с Java 8, еще одним быстрым и простым способом загрузки содержимого файла в Список массивов было бы использование Java Streams API :
Однако имейте в виду, что этот подход, как и Files.ReadAllLines () , будет работать только в том случае, если данные хранятся в строках.
Приведенный выше код не делает ничего особенного, и мы редко использовали бы потоки таким образом. Однако, поскольку мы загружаем эти данные в ArrayList , чтобы мы могли обработать их в первую очередь, потоки предоставляют отличный способ сделать это.
Мы можем легко сортировать/фильтровать/сопоставлять данные перед их сохранением в списке массивов :
Читайте также: