5

非常に大量のデータを処理するプロジェクトに取り組んでいます。私はたくさんの(数千の)zipファイルを持っており、それぞれに数千行(約8万行)の1つの単純なtxtファイルが含まれています。私が現在行っていることは次のとおりです。

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)));
...

このようにして、ファイルを1行ずつ読み取ることができますが、明らかに遅すぎます。読み取る必要がある多数のファイルと行を考えると、より効率的な方法でそれらを読み取る必要があります。

別のアプローチを探しましたが、何も見つかりませんでした。私が使用すべきだと思うのは、集中的な I/O 操作に適した Java nio API ですが、それらを zip ファイルで使用する方法がわかりません。

どんな助けでも本当に感謝します。

ありがとう、

マルコ

4

6 に答える 6

3

たくさんの (数千の) zip ファイルがあります。圧縮されたファイルはそれぞれ約 30 MB ですが、zip ファイル内の txt は約 60/70 MB です。このコードでファイルを読み取って処理するには、約 15 時間かかりますが、場合によって異なります。

エンベロープの裏計算をしてみましょう。

5000 個のファイルがあるとします。それらを処理するのに 15 時間かかる場合、これはファイルあたり約 10 秒に相当します。ファイルはそれぞれ約 30MB であるため、スループットは ~3MB/s です。

ZipFileこれは、解凍できる速度よりも 1 ~ 2 桁遅い速度です。

ディスクに問題があるか (ディスクはローカルですか、それともネットワーク共有ですか?)、ほとんどの時間を費やしているのは実際の処理です。

確実に調べる最善の方法は、プロファイラーを使用することです。

于 2012-05-24T15:20:47.053 に答える
3

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 はストリームを操作しているため、自由にジャンプできません。そのため、各エントリの EOF に到達して次のエントリ ヘッダーを読み取るために、すべての zip データを読み取って解凍する必要があります。

どういう意味ですか?ファイル システムに既に zip ファイルがある場合は、タスクに関係なく、ZipFile を使用して処理します。おまけとして、zip エントリに順次またはランダムにアクセスできます (パフォーマンスの低下はかなり小さくなります)。一方、ストリームを処理している場合は、ZipInputStream を使用してすべてのエントリを順番に処理する必要があります。

ここに例があります。3 つの 0.6Gb エントリを含む zip アーカイブ (合計ファイル サイズ = 1.6Gb) は、ZipFile を使用して 0.05 秒、ZipInputStream を使用して 18 秒で反復されました。

于 2015-03-29T16:05:19.450 に答える
1

次のように新しいファイル API を使用できます。

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でも機能すると思います。

于 2012-05-24T15:19:13.380 に答える