Чтение файла построчно в Java

В информатике файл - это ресурс, используемый для дискретной записи данных в запоминающее устройство компьютера. В Java ресурс обычно представляет собой объект, реализующий интерфейс AutoCloseable. Чтение файлов и ресурсов имеет множество применений: * Статистика, аналитика и отчеты * Машинное обучение * Работа с большими текстовыми файлами или журналами Иногда эти файлы могут быть абсурдно большими, при этом сохраняются гигабайты или терабайты, и чтение их целиком неэффективно. . Уметь читать

В информатике файл - это ресурс, используемый для дискретной записи данных в запоминающее устройство компьютера. В Java ресурс обычно представляет собой объект, реализующий интерфейс AutoCloseable

Чтение файлов и ресурсов имеет множество применений:

  • Статистика, аналитика и отчеты
  • Машинное обучение
  • Работа с большими текстовыми файлами или журналами

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

Возможность читать файл построчно дает нам возможность искать только релевантную информацию и останавливать поиск, как только мы нашли то, что ищем. Это также позволяет нам разбивать данные на логические части, как если бы файл был отформатирован в формате CSV.

Есть несколько различных вариантов на выбор, когда вам нужно прочитать файл построчно.

Сканер

Один из самых простых способов чтения файла построчно в Java может быть реализован с помощью класса Scanner. Сканер разбивает свой ввод на токены, используя шаблон разделителя, которым в нашем случае является символ новой строки:

 Scanner scanner = new Scanner(new File("filename")); 
 while (scanner.hasNextLine()) { 
 String line = scanner.nextLine(); 
 // process the line 
 } 

Метод hasNextLine() возвращает true если на входе этого сканера есть еще одна строка, но сам сканер не проходит мимо любого ввода и не считывает какие-либо данные в этот момент.

Чтобы прочитать строку и двигаться дальше, мы должны использовать метод nextLine() . Этот метод продвигает сканер мимо текущей строки и возвращает ввод, который не был достигнут изначально. Этот метод возвращает оставшуюся часть текущей строки, исключая любой разделитель строк в конце строки. Затем позиция чтения устанавливается в начало следующей строки, которая будет считана и возвращена при повторном вызове метода.

Поскольку этот метод продолжает поиск по входу в поисках разделителя строк, он может буферизовать весь вход при поиске конца строки, если разделители строк отсутствуют.

Буферизованный читатель

Класс BufferedReader представляет собой эффективный способ чтения символов, массивов и строк из потока ввода символов.

Как описано в названии, этот класс использует буфер. По умолчанию объем данных, которые буферизуются, составляет 8192 байта, но для повышения производительности может быть установлен произвольный размер:

 BufferedReader br = new BufferedReader(new FileReader(file), bufferSize); 

Файл или, скорее, экземпляр File не является подходящим источником данных для BufferedReader , поэтому нам нужно использовать FileReader , который расширяет InputStreamReader . Это удобный класс для чтения информации из текстовых файлов, и он не обязательно подходит для чтения необработанного потока байтов:

 try (BufferedReader br = new BufferedReader(new FileReader(file))) { 
 String line; 
 while ((line = br.readLine()) != null) { 
 // process the line 
 } 
 } 

Инициализация буферизованного считывателя была написана с использованием синтаксиса try-with-resources , специфичного для Java 7 или выше. Если вы используете старую версию, вам следует инициализировать переменную br try и закрыть ее в блоке finally

Вот пример предыдущего кода без синтаксиса try-with-resources:

 BufferedReader br = new BufferedReader(new FileReader(file)); 
 try { 
 String line; 
 while ((line = br.readLine()) != null) { 
 // process the line 
 } 
 } finally { 
 br.close(); 
 } 

Код будет перебирать строки предоставленного файла и останавливаться, когда встречает null строку, которая является концом файла.

Не запутайтесь, так как null не равен пустой строке, и файл будет прочитан до конца.

Метод линий

BufferedReader также имеет lines который возвращает Stream . Этот поток содержит строки, которые были прочитаны BufferedReader как его элементы.

Вы можете легко преобразовать этот поток в список, если вам нужно:

 List<String> list = new ArrayList<>(); 
 
 try (BufferedReader br = new BufferedReader(new FileReader(file))) { 
 list = br.lines().collect(Collectors.toList()); 
 } 

Чтение этого списка аналогично чтению потока, которое рассматривается в следующем разделе:

 list.forEach(System.out::println); 

Потоки Java 8

Если вы уже знакомы с потоками Java 8, вы можете использовать их как более чистую альтернативу устаревшему циклу:

 try (Stream<String> stream = Files.lines(Paths.get(fileName))) { 
 stream.forEach(System.out::println); 
 } 

Здесь мы снова используем синтаксис try-with-resources , инициализируя поток строк с помощью статического вспомогательного метода Files.lines() System.out::println используется в демонстрационных целях, и вы должны заменить ее любым кодом, который вы будете использовать для обработки своих строк текста.

Помимо чистого API, потоки очень полезны, когда вы хотите применить несколько операций к данным или отфильтровать что-то.

Предположим, у нас есть задача напечатать все строки, которые находятся в данном текстовом файле, и оканчиваются символом «/». Строки следует преобразовать в верхний регистр и отсортировать по алфавиту.

Изменив наш первоначальный пример Streams API, мы получим очень чистую реализацию:

 try (Stream<String> stream = Files.lines(Paths.get(fileName))) { 
 stream 
 .filter(s -> s.endswith("/")) 
 .sorted() 
 .map(String::toUpperCase) 
 .forEach(System.out::println); 
 } 

Метод filter() возвращает поток, состоящий из элементов этого потока, соответствующих заданному предикату. В нашем случае мы оставляем только те, которые заканчиваются на «/».

Метод map() возвращает поток, состоящий из результатов применения данной функции к элементам этого потока.

Метод toUpperCase() String помогает нам достичь желаемого результата и используется здесь как ссылка на метод, как и println из нашего предыдущего примера.

Метод sorted() возвращает поток, состоящий из элементов этого потока, отсортированных в соответствии с естественным порядком. Вы также можете предоставить собственный Comparator , и в этом случае сортировка будет выполняться в соответствии с ним.

Хотя порядок операций может быть изменен для методов filter() , sorted() и map() forEach() всегда следует помещать в конец, поскольку это операция терминала. Он возвращает void и в этом отношении к нему больше ничего нельзя привязать.

Apache Commons

Если вы уже используете Apache Commons в своем проекте, вы можете использовать помощник, который считывает все строки из файла в List<String> :

 List<String> lines = FileUtils.readLines(file, "UTF-8"); 
 for (String line: lines) { 
 // process the line 
 } 

Помните, что этот подход считывает все строки из файла в lines и только после этого начинается выполнение цикла for . Это может занять много времени, и вам следует дважды подумать, прежде чем использовать его для больших текстовых файлов.

Заключение

В Java существует несколько способов чтения файла построчно, и выбор подходящего подхода полностью зависит от программиста. Вы должны подумать о размере файлов, которые вы планируете обрабатывать, требованиях к производительности, стиле кода и библиотеках, которые уже есть в проекте. Обязательно протестируйте некоторые угловые случаи, такие как огромные, пустые или несуществующие файлы, и вам будет хорошо использовать любой из предоставленных примеров.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus