Вопрос по java, performance – Чтение zip-файлов эффективно на Java

4

Я работаю над проектом, который работает с очень большим количеством данных. У меня есть много (тысячи) zip-файлов, каждый из которых содержит ОДИН простой текстовый файл с тысячами строк (около 80 тыс. Строк). Что я сейчас делаю, так это:

for(File zipFile: dir.listFiles()){
ZipFile zf = new ZipFile(zipFile);
ZipEntry ze = (ZipEntry) zf.entries().nextElement();
BufferedReader in = new BufferedReader(new InputStreamReader(zf.getInputStream(ze)));
...

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

Я искал другой подход, но ничего не смог найти. Я думаю, что я должен использовать API Java Java, предназначенные для интенсивных операций ввода-вывода, но я не знаю, как использовать их с zip-файлами.

Любая помощь будет очень признательна.

Благодарность

Марко

Я полагаю, что обработка занимает здесь много времени. Вам нужно измерить. Попробуйте только часть чтения, без какой-либо обработки. user207421
Вы делаете классическую ошибку, думая, что API nio делают ваш код быстрее. API nio могут сделать ваш код более Масштабируемой обработка большего количества потоков с меньшим количеством потоков, но это не обязательно делает вещиБыстре. jtahlborn
Сначала вы должны определить, тратит ли большая часть вашего времени на чтение из zip-файлов или на обработку строк текста. Что вы делаете с каждой строкой в текстовых файлах? Jack Edmonds
Насколько большие файлы? Сколько времени нужно, чтобы прочитать их с помощью этого кода? Сколько времени нужно, чтобы скопировать их в/dev/null? NPE
@ aix Размер ZIP-файла - около 30 МБ каждый, а txt внутри zip-файла - около 60/70 МБ. Либо размер и количество строк не являются фиксированными, они могут изменяться, но теоретически они должны всегда быть одинаковыми по размеру и количеству строк. Чтение и обработка файлов с этим кодом занимает много часов, около 15, но это зависит от многих факторов. smellyarmpits

Ваш Ответ

5   ответов
3

вляет около 30 МБ каждый, а txt внутри zip-файла - около 60/70 МБ. Чтение и обработка файлов с этим кодом занимает много часов, около 15, но это зависит.

Давайте сделаем некоторые расчёты.

Допустим, у вас есть 5000 файлов. Если их обработка занимает 15 часов, это равняется ~ 10 секундам на файл. Размер файлов составляет около 30 МБ, поэтому пропускная способность составляет ~ 3 МБ / с.

Это на один-два порядка медленнее, чем скорость, с которойZipFile может распаковать вещи.

Либо есть проблема с дисками (локальными или сетевыми?), Либо фактическая обработка занимает большую часть времени.

Лучший способ узнать наверняка - использовать профилировщик.

Ну вот и все. В настоящее время я работаю над небольшой частью всех файлов: я искренне не помню ни времени, необходимого для их обработки, ни времени, потраченного на обработку ВСЕХ файлов (не только тех, которые у меня есть). Во всяком случае, мы говорим о часах. Тем не менее, я хотел бы знать, каков наиболее эффективный способ чтения этих файлов. С помощью API Java nio мы можем эффективно читать файлы, используя файловые каналы, но это не представляется возможным для zip-файлов. Если вы знаете, есть ли возможность сделать это с другими видами сжатых файлов вместо zips, пожалуйста, дайте мне знать. Спасибо всем, Марк smellyarmpits
1

Правильный способ итерации файла zip

final ZipFile file = new ZipFile( FILE_NAME );
try
{
final Enumeration<? extends ZipEntry> entries = file.entries();
while ( entries.hasMoreElements() )
{
    final ZipEntry entry = entries.nextElement();
    System.out.println( entry.getName() );
    //use entry input stream:
    readInputStream( file.getInputStream( entry ) )
}
}
finally
{
file.close();
}

private static int readInputStream( final InputStream is ) throws IOException {
final byte[] buf = new byte[ 8192 ];
int read = 0;
int cntRead;
while ( ( cntRead = is.read( buf, 0, buf.length ) ) >=0  )
{
    read += cntRead;
}
return read;
}

Zip-файл состоит из нескольких записей, каждая из которых имеет поле, содержащее количество байтов в текущей записи. Таким образом, легко выполнить итерации всех записей zip-файла без фактической распаковки данных. java.util.zip.ZipFile принимает имя файла / файла и использует произвольный доступ для перехода между позициями файла. java.util.zip.ZipInputStream, с другой стороны, работает с потоками, поэтому он не может свободно прыгать. Вот почему он должен прочитать и распаковать все zip-данные, чтобы достичь EOF для каждой записи и прочитать заголовок следующей записи.

Что это означает? Если у вас уже есть zip-файл в вашей файловой системе - используйте ZipFile для его обработки независимо от вашей задачи. В качестве бонуса вы можете получить доступ к zip-записям последовательно или случайным образом (с довольно небольшим снижением производительности) С другой стороны, если вы обрабатываете поток, вам нужно обрабатывать все записи последовательно, используя ZipInputStream.

Вот пример. Zip-архив (общий размер файла = 1,6 ГБ), содержащий три записи по 0,6 ГБ, был повторен за 0,05 секунды с использованием ZipFile и за 18 секунд с использованием ZipInputStream.

Копия вставлена из Java-performance.info / как к итерации-ZIP-файлы-записей plastique
0

Path jarPath = Paths.get(...);
try (FileSystem jarFS = FileSystems.newFileSystem(jarPath, null)) {
    Path someFileInJarPath = jarFS.getPath("/...");
    try (ReadableByteChannel rbc = Files.newByteChannel(someFileInJarPath, EnumSet.of(StandardOpenOption.READ))) {
        // read file
    }
}

Код для jar-файлов, но я думаю, что он должен работать и для zip-файлов.

Нет ответа. Он утверждает, что его время потрачено Чтение файлы, не находя их. user207421
? ОП явно попросил подход «API Java Java». Если подумать, OP мог бы искать подход java.nio.channels, а не java.nio.file. Puce
Я обновил свой пример, чтобы также использовать API java.nio.channels. Я не проводил никакого анализа производительности и не знаю, поможет ли он в этом случае. Тем не менее, java.nio.file является предпочтительным API в Java SE 7. Puce
0

Ты можешь попробовать этот код

try
    {

        final ZipFile zf = new ZipFile("C:/Documents and Settings/satheesh/Desktop/POTL.Zip");

        final Enumeration<? extends ZipEntry> entries = zf.entries();
        ZipInputStream zipInput = null;

        while (entries.hasMoreElements())
        {
            final ZipEntry zipEntry=entries.nextElement();
            final String fileName = zipEntry.getName();
        // zipInput = new ZipInputStream(new FileInputStream(fileName));
            InputStream inputs=zf.getInputStream(zipEntry);
            //  final RandomAccessFile br = new RandomAccessFile(fileName, "r");
                BufferedReader br = new BufferedReader(new InputStreamReader(inputs, "UTF-8"));
                FileWriter fr=new FileWriter(f2);
            BufferedWriter wr=new BufferedWriter(new FileWriter(f2) );

            while((line = br.readLine()) != null)
            {
                wr.write(line);
                System.out.println(line);
                wr.newLine();
                wr.flush();
            }
            br.close();
            zipInput.closeEntry();
        }


    }
    catch(Exception e)
    {
        System.out.print(e);
    }
    finally
    {
        System.out.println("\n\n\nThe had been extracted successfully");

    }

этот код работает хорошо.

0

Zlib, который Java использует внутренне peroform zip / unzip. Он требует, чтобы вы исправили исходники zlib с помощью Interl'sIPP paches. Я сделал Тест показывает увеличение пропускной способности в 1,4–3 раза.

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