Самый быстрый способ получить доступ к заданным строкам текстового файла с использованием и без использования GZip и Jar File (GZip в памяти?) - PullRequest
1 голос
/ 18 января 2012

Я дал число (5-7) больших текстовых файлов UTF8 (7 МБ). В Юникоде их размер составляет около 15 МБ каждый.

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

Кроме того, пользователь может искать данное слово во всех файлах.

На данный момент я использую код:

private static void loadFile(String filename, int startLine, int stopLine) {
    try {
        FileInputStream fis = new FileInputStream(filename);                
        InputStreamReader isr = new InputStreamReader(fis, "UTF8");
        BufferedReader reader = new BufferedReader(isr);
        for (int j = startLine; j <= stopLine; j++) {
            //here I add HTML tags
            //or do string comparison in case of search by the user 
            sb.append(reader.readLine());
        }
        reader.close();
    } catch (FileNotFoundException e) {
        System.out.println(e);
    } catch (IOException e) {
        System.out.println(e);
    }
}

Теперь мои вопросы:

Поскольку количество частей каждого файла известно, в моем случае 67 (для каждого файла), я мог бы создать 67 файлов меньшего размера. Это будет «быстрее» загружать данную часть, но будет медленнее, когда я выполняю поиск, так как я должен открыть каждый из файлов 67.

Я не проводил тестирование, но, по моим ощущениям, открытие 67 файлов в случае поиска намного дольше, чем время выполнения пустого reader.readlines при загрузке части файла.

Так что в моем случае лучше иметь один файл большего размера. Вы согласны с этим?

Если я помещу каждый большой файл в ресурс, я имею в виду файл Jar, будет ли производительность хуже, если да, будет ли она значительно хуже?

И связанный с этим вопрос: что, если я заархивирую каждый файл, чтобы сэкономить размер. Насколько я понимаю, Jar-файл - это просто zip-файл.

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

Если распаковка отсутствует в памяти, кто-то может отредактировать мой код для использования zip-файла.

Последний вопрос и самый важный для меня. Я мог бы увеличить всю производительность, если бы все выполнялось в памяти, но из-за юникода и довольно больших файлов это могло легко привести к куче памяти более 100 МБ. Есть ли возможность загрузить zip-файл в память и поработать над этим. Это было бы быстро и использовало бы только немного памяти.

Краткое изложение вопросов

  1. В моем случае, 1 большой файл лучше, чем множество маленьких.

  2. Если файлы заархивированы, процесс распаковки (GZipInputStream) выполняется в памяти. Разархивирован ли весь файл в памяти, а затем получен доступ или возможен ли доступ к нему непосредственно на диске.

  3. Если да на вопрос 2, может ли кто-нибудь отредактировать мой код, чтобы иметь возможность это сделать?

  4. САМОЕ ВАЖНОЕ: возможно ли загрузить файл zip в память и как?

Надеюсь, мои вопросы достаточно ясны. ; -)

ОБНОВЛЕНИЕ : Спасибо Майку за подсказку getResourceAsStream, у меня все работает

Обратите внимание, что бенчмаркинг дает эффективную загрузку файла Gzip, но в большинстве случаев он слишком медленный.

~ 200 мс для файла gzip ~ 125 мс для стандартного файла, что в 1,6 раза быстрее.

Предполагается, что папка ресурсов называется ресурсами

private static void loadFile(String filename, int startLine, int stopLine) {
    try {                           
        GZIPInputStream zip = new GZIPInputStream(this.class.getResourceAsStream("resources/"+filename));            
        InputStreamReader isr = new InputStreamReader(zip, "UTF8");
        BufferedReader reader = new BufferedReader(isr);
        for (int j = startLine; j <= stopLine; j++) {
            //here I add HTML tags
            //or do string comparison in case of search by the user 
            sb.append(reader.readLine());
        }
        reader.close();
    } catch (FileNotFoundException e) {
        System.out.println(e);
    } catch (IOException e) {
        System.out.println(e);
    }
}

Ответы [ 2 ]

2 голосов
/ 18 января 2012

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

Но, чтобы ответить на ваши вопросы более прямо:

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

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

  3. Я не могу исправить ваш код напрямую, но я могу предложить поискать getResourceAsStream: http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getResourceAsStream%28java.lang.String%29 Эта функция откроет файл, который находится в файле zip / jar, и даст вам доступ к нему в виде потока, автоматически распаковывая его в памяти по мере использования.

  4. Если вы рассматриваете это как ресурс, java сделает все за вас, вам придется ознакомиться с некоторыми особенностями обработки ресурсов, но java должен справиться с этим довольно разумно.

1 голос
/ 18 января 2012
  1. Я думаю, вам будет проще загрузить файл (ы) в память. Затем вы можете перемещаться в любую часть файла, которая вам нужна. Взгляните на RandomAccessFile для этого.

  2. GZipInputStream считывает файлы в память как буферизованный поток.

  3. Это совсем другой вопрос:)

  4. Опять же, zip-файл будет распакован в памяти в зависимости от того, какой класс вы используете для его открытия.

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