Как читать большие файлы (одну непрерывную строку) в Java? - PullRequest
1 голос
/ 26 февраля 2020

Я пытаюсь прочитать очень большой файл (~ 2 ГБ). Содержимое - это непрерывная строка с предложениями (я хотел бы разделить их на «.»). Независимо от того, как я стараюсь, я получаю Outofmemoryerror.

    BufferedReader in = new BufferedReader(new FileReader("a.txt"));
    String read = null;
    int i = 0;
    while((read = in.readLine())!=null) {
        String[] splitted = read.split("\\.");
        for (String part: splitted) {
            i+=1;
            users.add(new User(i,part));
            repository.saveAll(users);
        }
    }

также,

inputStream = new FileInputStream(path);
    sc = new Scanner(inputStream, "UTF-8");
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        // System.out.println(line);
    }
    // note that Scanner suppresses exceptions
    if (sc.ioException() != null) {
        throw sc.ioException();
    }

Содержимое файла (состоит из случайных слов с полной остановкой после 10 слов) :

fmfbqi .xcdqnjqln kvjhw pexrbunnr cgvrqlr fpaczdegnb puqzjdbp gcfxne jawml aaiwwmo ugzoxn .opjc fmfbqi .xcdqnjqln kvjhw pexrbunnr cgvrqlr fpaczdegnb puqzjdbp gcfxne jawml aaiwwmo ugzoxn .opjc  (so on)

Пожалуйста, помогите!

1 Ответ

3 голосов
/ 26 февраля 2020

Итак, прежде всего, основываясь на комментариях к вашему вопросу, как сказал Йоахим Зауэр:

Если нет новых строк, то есть только одна строка и, следовательно, только один номер строки.

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

Давайте пройдем мимо этого и предположим, что, возможно, есть символы новой строки - или еще лучше, предположим, что символ . вы ' Повторное разделение предназначено для псевдо-замены новой строки.

Scanner - неплохой подход, хотя есть и другие. Так как вы предоставили Scanner, давайте продолжим с этим, но вы хотите убедиться, что вы оборачиваете его вокруг BufferedReader. У вас явно недостаточно памяти, и BufferedReader позволяет вам читать «куски» файла, как буферизовано BufferedReader, в то же время используя функциональность Scanner, совершенно невидимую вам как Вызывает, что происходит буферизация:

Scanner sc = new Scanner(new BufferedReader(new FileReader(new File("a.txt")), 10*1024));

То, что это в основном делает, позволяет функции Scanner, как вы ожидаете, но позволяет буферизовать 10 МБ за раз, минимизируя объем памяти. Теперь вы просто продолжаете вызывать

sc.useDelimiter("\\.");
for(int i = 0; sc.hasNext(); i++) {
    String psudeoLine = sc.next();
    //store line 'i' in your database for this psudeo-line
    //DO NOT store psudeoLine anywhere else - you don't have memory for it
}

Поскольку у вас недостаточно памяти, ясно, что итерация (и повторение) заключается в том, чтобы не сохранять какую-либо часть файла в пространстве кучи вашей JVM после читая это. Прочтите его, используйте так, как вам нужно, и дайте ему пометиться для сборки мусора в JVM. В вашем случае вы упоминаете, что хотите сохранить строки psudeo в базе данных, поэтому вы хотите прочитать строку psudeo, сохранить ее в базе данных и просто отбросить ее.

Есть и другие вещи, на которые нужно указать здесь, например, настройка параметров JVM, но я не решаюсь даже упомянуть об этом, потому что установка высокого уровня памяти JVM также является плохой идеей - еще один грубый метод. Нет ничего плохого в том, чтобы увеличить максимальный размер кучи памяти JVM, но лучше научиться управлять памятью, если вы все еще учитесь писать программы. Позже у вас будет меньше проблем, когда вы перейдете к профессиональному развитию.

Кроме того, я упомянул Scanner и BufferedReader, потому что вы упомянули об этом в своем вопросе, но я думаю, что стоит проверить java .nio.file.Path.lines () , как указал де Хаар, также хорошая идея. Это в основном делает то же самое, что и код, который я явно выложил, с оговоркой, что он по-прежнему делает только 1 строку за раз без возможности изменить то, что вы «разделяете». Поэтому, если ваш текстовый файл содержит одну строку, это все равно вызовет у вас проблему, и вам все равно понадобится что-то вроде сканера для фрагментации строки.

...