Java прочитать большой файл

Обновлено: 03.07.2024

Я имею в виду, есть ли что-то эквивалентное этому в Java?:

если не. каков "оптимальный способ" сделать это.

Edit:
Я предпочитаю путь в стандартных библиотеках Java. Я не могу использовать сторонние библиотеки..

AFAIK, нет единого лайнера со стандартными библиотеками. Типичный подход со стандартными библиотеками будет примерно таким:

  • для того чтобы читать текст из файла, использовать FileInputStream
  • если производительность важна и Вы читаете большие файлы, было бы целесообразно обернуть поток в BufferedInputStream
  • поток должен быть закрыт абонент

но в стандартных классах java такой утилиты нет. Если вы (по какой-то причине) не хотите внешних библиотек, вам придется переопределить его. здесь некоторые примеры, и альтернативно, вы можете увидеть, как он реализуется commons-io или Guava.

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

или читать строки:

конечно, я уверен, что есть другие сторонние библиотеки, которые сделают это так же легко - я просто наиболее знаком с Guava.

Java 7 улучшает это жалкое состояние дел с Files класс (не путать с класс с тем же именем), вы можете получить все строки из файла - без внешних библиотек - с:

или в одну строку:

Если вам нужно что-то из коробки с чистым JDK, это отлично работает. Тем не менее, почему вы пишете Java без гуавы?

на Java 8 (без внешних библиотек) вы можете использовать потоки. Этот код считывает файл и помещает все строки, разделенные', ' в строку.

С помощью JDK / 11 вы можете прочитать полный файл на Path в виде строки с использованием Files.readString(Path path) :

документация метода из JDK гласит следующее:

внешние библиотеки не требуются. Содержимое файла будет буферизовано перед преобразованием в string.

вот 3 способа прочитать текстовый файл в одной строке, не требуя цикла. Я задокументировал 15 способов чтения из файла в Java а это из той статьи.

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

1) java.НИО.файл.Файлы.readAllLines() - кодировка по умолчанию

2) Ява.НИО.файл.Файлы.readAllLines () - явная кодировка

внешние библиотеки не требуются. Содержимое файла будет буферизовано перед преобразованием в string.

В этом уроке мы будем читать и записывать файлы на 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, и, кроме того, код немного более удобен для обслуживания и чтения.

Мне нужен совет от кого-то, кто очень хорошо знает Java и проблемы с памятью. У меня есть большой файл (что-то вроде 1.5 GB), и мне нужно вырезать этот файл во многих (100 небольших файлов, например) меньших файлах.

Я вообще знаю, как это сделать (с помощью BufferedReader ), но я хотел бы знать, есть ли у вас какие-либо советы относительно памяти или советы, как сделать это быстрее.

мой файл содержит текст, он не является двоичным, и у меня есть около 20 символов на строку.

во-первых, если ваш файл содержит двоичные данные, то с помощью BufferedReader было бы большой ошибкой (потому что вы будете преобразовывать данные в строку, которая не нужна и может легко повредить данные); вы должны использовать BufferedInputStream вместо. Если это текстовые данные, и вам нужно разделить их по линиям, а затем использовать BufferedReader ОК (если файл содержит строки разумной длины).

Что касается памяти, не должно быть никаких проблем, если вы используете буфер приличного размера (я бы использовал минимум 1 МБ, чтобы убедиться, что HD делает в основном последовательное чтение и запись).

если скорость оказывается проблемой, вы можете взглянуть на java.nio пакеты-это, предположительно, быстрее, чем java.io ,

чтобы сохранить память, не храните/не дублируйте данные в памяти (т. е. не назначайте их переменным вне цикла). Просто обработайте вывод тут как только вход поступает.

Это действительно не имеет значения, используете ли вы BufferedReader или нет. Это не будет стоить значительно больше памяти, как некоторые неявно предполагают. Это будет в лучшем случае только несколько % от производительности. То же самое относится к использованию NIO. Это только улучшит масштабируемость, а не использование памяти. Это будет интересно только тогда, когда у вас есть сотни потоков, работающих в одном файле.

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

вы можете рассмотреть возможность использования файлов, сопоставленных с памятью, через FileChannels .

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

в резюме, для большой производительности, вы должны:

  1. избегайте доступа к диску.
  2. избежать доступа к базовой операционной системе.
  3. избегайте вызовов методов.
  4. избегать обработки байтов и символов по отдельности.

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

Это нужно сделать на Java? Т. е. должна ли она быть независимой от платформы? Если нет, я бы предложил использовать ' split ' команда в *nix. Если вы действительно хотите, вы можете выполнить эту команду через свою программу java. Хотя я не тестировал, я полагаю, что он работает быстрее, чем любая реализация Java IO, которую вы могли бы придумать.

Я хочу прочитать последние n строк очень большого файла, не читая весь файл в любой буфер / область памяти с помощью Java.

Я осмотрел API JDK и Apache Commons I / O и не смог найти тот, который подходит для этой цели.

Я думал о том, как хвост или меньше делает это в UNIX. Я не думаю, что они загружают весь файл, а затем показывают последние несколько строк файла. Должен быть аналогичный способ сделать то же самое и в Java.

если вы используете RandomAccessFile , вы можете использовать length и seek чтобы попасть в конкретную точку в конце файла, а затем читать дальше.

если вы обнаружите, что было недостаточно линий, отступите с этой точки и повторите попытку. Как только вы выяснили, где N - Я последняя строка начинается, вы можете искать там и просто читать и печатать.

первоначальное предположение наилучшего предположения может быть сделано на основе ваших данных свойства. Например, если это текстовый файл, возможно, длина строки не будет превышать в среднем 132, поэтому, чтобы получить последние пять строк, начните 660 символов до конца. Затем, если вы ошиблись, попробуйте еще раз в 1320 (вы даже можете использовать то, что вы узнали из последних 660 символов, чтобы настроить это-пример: если эти 660 символов были всего три строки, следующая попытка может быть 660 / 3 * 5, плюс, может быть, немного больше на всякий случай).

Я нашел самый простой способ сделать с помощью ReversedLinesFileReader С Apache commons-io API-интерфейс. Этот метод даст вам строку снизу вверх файла, и вы можете указать n_lines значение для указания количества линий.

RandomAccessFile-хорошее место для начала, как описано в других ответах. Есть один важный нюанс хотя.

если ваш файл не закодирован с кодировкой один байт на символ, readLine() метод не будет работать для вас. И readUTF() не будет работать ни при каких обстоятельствах. (Он читает строку, которой предшествует число символов . )

вместо этого вам нужно будет убедиться, что вы ищете маркеры конца строки таким образом, чтобы уважать границы символов кодировки. Для кодировок фиксированной длины (например, вкусы UTF-16 или UTF-32) необходимо извлечь символы, начиная с байтовых позиций, которые делятся на размер символов в байтах. Для кодировок переменной длины (например, UTF-8) вам нужно найти байт, который должны быть первым байтом символа.

в случае UTF-8 первым байтом символа будет 0xxxxxxx или 110xxxxx или 1110xxxx или 11110xxx . Все остальное - либо второй / третий байт, либо незаконная последовательность UTF-8. См.Стандарт Unicode, Версия 5.2, Глава 3.9, таблица 3-7. Это означает, как указывает обсуждение комментариев, что любые байты 0x0A и 0x0D в правильно закодированном потоке UTF-8 будут представлять символ LF или CR. Таким образом, подсчет байтов является допустимой стратегией реализации (для UTF-8).

определив правильную границу символа, вы можете просто позвонить new String(. ) передача массива байтов, смещение, количество и кодирование, а затем повторно вызовите String.lastIndexOf(. ) для подсчета конца строк.

обратите внимание, что в Apache Commons Collections 4 Этот класс, похоже, был переименован в CircularFifoQueue

У меня была аналогичная проблема, но я не понял других решений.

я использовал это. Надеюсь, это простой код.

вот лучший способ я нашел, чтобы сделать это. Простой и довольно быстрый и оперативную память.

Читайте также: