Чтение больших файлов и выполнение некоторых операций в Java - PullRequest
2 голосов
/ 02 марта 2012

Прежде всего, я бы попытался объяснить, что мне нужно делать. Мне нужно прочитать файл (размер которого может быть от 1 байта до 2 ГБ), максимум 2 ГБ, потому что я пытаюсь использовать MappedByteBuffer для быстрого чтения. Возможно, позже я попытаюсь прочитать файл кусками, чтобы прочитать файлы произвольного размера.

Когда я читаю файл, я конвертирую его байты и преобразую их (используя кодировку ASCII ) в символы, которые позже я помещаю в StringBuilder , а затем помещаю этот String Builder в ArrayList

Однако мне также нужно сделать следующее:

  1. Пользователь может ввести blockSize, которое представляет собой число символов, которые я должен прочитать в StringBuilder (в основном это число байтов файла, преобразованных в символы)

  2. После того, как я собрал определяемое пользователем количество символов, я создаю копию String Builder и помещаю ее в список массивов

Все шаги выполняются для каждого прочитанного символа. Проблема в String Builder, поскольку, если файл большой (<500 МБ), я получаю исключение <strong>OutOfMemoryError .

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:45)
    at java.lang.StringBuilder.<init>(StringBuilder.java:80)
    at java.lang.StringBuilder.<init>(StringBuilder.java:106)
    at borrows.wheeler.ReadFile.readFile(ReadFile.java:43)
Java Result: 1 

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

public class ReadFile {

    //matrix block size
    public int blockSize = 100;

    public int charCounter = 0;

    public ArrayList readFile(File file) throws FileNotFoundException, IOException {

        FileChannel fc = new FileInputStream(file).getChannel();
        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int) fc.size());

        ArrayList characters = new ArrayList(); 
        int counter = 0;
        StringBuilder sb = new StringBuilder();//blockSize-1

        while (mbb.hasRemaining()) {   

        char charAscii = (char)mbb.get();


            counter++;
            charCounter++;

             if (counter == blockSize){

                sb.append(charAscii);
                characters.add(new StringBuilder(sb));//new StringBuilder(sb)
                sb.delete(0, sb.length());
                counter = 0;

            }else{

                sb.append(charAscii);

             }

         if(!mbb.hasRemaining()){
            characters.add(sb);
        }



        }
        fc.close();
        return characters;


    }

}

EDIT : Я делаю преобразование Барроуза-Уилера. Там я должен прочитать каждый файл, а затем по размеру блока создать столько матриц, сколько нужно. ну, я верю, что вики объяснит лучше меня:

http://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform

Ответы [ 2 ]

1 голос
/ 02 марта 2012

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

Когда я читаю файл, я конвертирую его байты и конвертирую их (используя ASCII кодирование) в символы, которые позже я положил в StringBuilder, а затем я поместите этот String Builder в ArrayList

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

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

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

1 голос
/ 02 марта 2012

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

Сколько у вас памяти?Вы на 64-битной системе с 64-битной Java?Сколько кучи памяти выделено (например, с использованием параметра -Xmx)?

Имейте в виду, что вам потребуется как минимум вдвое больше памяти, чем размер файла, потому что Java использует Unicode UTF-16, который использует вминимум 2 байта для каждого символа, но вы вводите один байт на символ.Таким образом, чтобы загрузить файл объемом 2 ГБ, вам понадобится как минимум 4 ГБ, выделенных для кучи только для хранения этих текстовых данных.

Кроме того, вам нужно разобраться в логике вашего кода - вы делаетето же самое sb.append(charAscii) в if и else, и вы проверяете !mbb.hasRemaining() в каждой итерации цикла while((mbb.hasRemaining()).

Как я спросил в вашем предыдущем вопросе, нужно ли вамхранить StringBuilders, или получающиеся строки будут в порядке?Хранение строк позволит сэкономить место, потому что StringBuilder выделяет память большими кусками (я думаю, что она удваивается по размеру каждый раз, когда заканчивается пространство!), Поэтому может тратить много.

Если вам действительно нужно использовать StringBuilders, то, если предварительно установить для них значение blockSize, код станет более эффективным (и более быстрым).

...