Считайте большие файлы в Java

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

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

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

59
задан Sergey Brunov 18 September 2016 в 17:23
поделиться

8 ответов

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

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

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

{{ 1}}
29
ответ дан 24 November 2019 в 18:29
поделиться

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

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

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

Начальный пример:

String encoding = "UTF-8";
int maxlines = 100;
BufferedReader reader = null;
BufferedWriter writer = null;

try {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding));
    int count = 0;
    for (String line; (line = reader.readLine()) != null;) {
        if (count++ % maxlines == 0) {
            close(writer);
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding));
        }
        writer.write(line);
        writer.newLine();
    }
} finally {
    close(writer);
    close(reader);
}
34
ответ дан 24 November 2019 в 18:29
поделиться

Вы можете использовать java.nio, который быстрее, чем классический поток ввода / вывода:

http://java.sun.com/javase/6 /docs/technotes/guides/io/index.html

1
ответ дан 24 November 2019 в 18:29
поделиться

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

0
ответ дан 24 November 2019 в 18:29
поделиться

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

4
ответ дан 24 November 2019 в 18:29
поделиться

Вы можете рассмотреть возможность использования отображенных в память файлов через FileChannel s.

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

Связанный ответ: Java NIO FileChannel по сравнению с производительностью / полезностью FileOutputstream

13
ответ дан 24 November 2019 в 18:29
поделиться

Это очень хорошая статья: http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/

Таким образом, для повышения производительности вам следует:

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

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

5
ответ дан 24 November 2019 в 18:29
поделиться

Не используйте чтение без аргументов. Это очень медленно. Лучше прочитать его в буфер и быстро переместить в файл.

Используйте bufferedInputStream, потому что он поддерживает двоичное чтение.

И все.

0
ответ дан 24 November 2019 в 18:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: