web-dev-qa-db-ja.com

CommonsCompressを使用してディレクトリをtar.gzに圧縮します

Commonscompressライブラリを使用してディレクトリのtar.gzを作成するときに問題が発生します。私は次のようなディレクトリ構造を持っています。

parent/
    child/
        file1.raw
        fileN.raw

次のコードを使用して圧縮を行っています。例外なく正常に動作します。ただし、そのtar.gzを解凍しようとすると、「childDirToCompress」という名前のファイルが1つ取得されます。正しいサイズなので、タール処理でファイルが互いに明確に追加されます。必要な出力はディレクトリです。何が間違っているのか理解できません。賢明なコモンズコンプレッサーは私を正しい道に導くことができますか?

CreateTarGZ() throws CompressorException, FileNotFoundException, ArchiveException, IOException {
            File f = new File("parent");
            File f2 = new File("parent/childDirToCompress");

            File outFile = new File(f2.getAbsolutePath() + ".tar.gz");
            if(!outFile.exists()){
                outFile.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(outFile);

            TarArchiveOutputStream taos = new TarArchiveOutputStream(new GZIPOutputStream(new BufferedOutputStream(fos)));
            taos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR); 
            taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
            addFilesToCompression(taos, f2, ".");
            taos.close();

        }

        private static void addFilesToCompression(TarArchiveOutputStream taos, File file, String dir) throws IOException{
            taos.putArchiveEntry(new TarArchiveEntry(file, dir));

            if (file.isFile()) {
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                IOUtils.copy(bis, taos);
                taos.closeArchiveEntry();
                bis.close();
            }

            else if(file.isDirectory()) {
                taos.closeArchiveEntry();
                for (File childFile : file.listFiles()) {
                    addFilesToCompression(taos, childFile, file.getName());

                }
            }
        }
11
awfulHack

何がうまくいかなかったのか正確にはわかりませんが、グーグルキャッシュを精査して実用的な例を見つけました。タンブルウィードでごめんなさい!

public void CreateTarGZ()
    throws FileNotFoundException, IOException
{
    try {
        System.out.println(new File(".").getAbsolutePath());
        dirPath = "parent/childDirToCompress/";
        tarGzPath = "archive.tar.gz";
        fOut = new FileOutputStream(new File(tarGzPath));
        bOut = new BufferedOutputStream(fOut);
        gzOut = new GzipCompressorOutputStream(bOut);
        tOut = new TarArchiveOutputStream(gzOut);
        addFileToTarGz(tOut, dirPath, "");
    } finally {
        tOut.finish();
        tOut.close();
        gzOut.close();
        bOut.close();
        fOut.close();
    }
}

private void addFileToTarGz(TarArchiveOutputStream tOut, String path, String base)
    throws IOException
{
    File f = new File(path);
    System.out.println(f.exists());
    String entryName = base + f.getName();
    TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName);
    tOut.putArchiveEntry(tarEntry);

    if (f.isFile()) {
        IOUtils.copy(new FileInputStream(f), tOut);
        tOut.closeArchiveEntry();
    } else {
        tOut.closeArchiveEntry();
        File[] children = f.listFiles();
        if (children != null) {
            for (File child : children) {
                System.out.println(child.getName());
                addFileToTarGz(tOut, child.getAbsolutePath(), entryName + "/");
            }
        }
    }
}
12
awfulHack

私はこの解決策に従いましたが、より大きなファイルセットを処理するまで機能し、15000〜16000ファイルの処理後にランダムにクラッシュしました。次の行はファイルハンドラーをリークしています:

IOUtils.copy(new FileInputStream(f), tOut);

また、OSレベルで「開いているファイルが多すぎます」というエラーでコードがクラッシュしました。次の小さな変更で問題が修正されました。

FileInputStream in = new FileInputStream(f);
IOUtils.copy(in, tOut);
in.close();
14
user3613365

私は次のことをすることになりました:

public URL createTarGzip() throws IOException {
    Path inputDirectoryPath = ...
    File outputFile = new File("/path/to/filename.tar.gz");

    try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            GzipCompressorOutputStream gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream);
            TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(gzipOutputStream)) {

        tarArchiveOutputStream.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
        tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);

        List<File> files = new ArrayList<>(FileUtils.listFiles(
                inputDirectoryPath,
                new RegexFileFilter("^(.*?)"),
                DirectoryFileFilter.DIRECTORY
        ));

        for (int i = 0; i < files.size(); i++) {
            File currentFile = files.get(i);

            String relativeFilePath = new File(inputDirectoryPath.toUri()).toURI().relativize(
                    new File(currentFile.getAbsolutePath()).toURI()).getPath();

            TarArchiveEntry tarEntry = new TarArchiveEntry(currentFile, relativeFilePath);
            tarEntry.setSize(currentFile.length());

            tarArchiveOutputStream.putArchiveEntry(tarEntry);
            tarArchiveOutputStream.write(IOUtils.toByteArray(new FileInputStream(currentFile)));
            tarArchiveOutputStream.closeArchiveEntry();
        }
        tarArchiveOutputStream.close();
        return outputFile.toURI().toURL();
    }
}

これにより、他のソリューションで発生するいくつかのEdgeケースが処理されます。

7
merrick

私が使用しているもの(_Files.walk_ API経由)では、gzip(tar(youFile));をチェーンできます

_public static File gzip(File fileToCompress) throws IOException {

    final File gzipFile = new File(fileToCompress.toPath().getParent().toFile(),
            fileToCompress.getName() + ".gz");

    final byte[] buffer = new byte[1024];

    try (FileInputStream in = new FileInputStream(fileToCompress);
            GZIPOutputStream out = new GZIPOutputStream(
                    new FileOutputStream(gzipFile))) {

        int len;
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }

    return gzipFile;
}

public static File tar(File folderToCompress) throws IOException, ArchiveException {

    final File tarFile = Files.createTempFile(null, ".tar").toFile();

    try (TarArchiveOutputStream out = (TarArchiveOutputStream) new ArchiveStreamFactory()
            .createArchiveOutputStream(ArchiveStreamFactory.TAR,
                    new FileOutputStream(tarFile))) {

        out.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);

        Files.walk(folderToCompress.toPath()) //
                .forEach(source -> {

                    if (source.toFile().isFile()) {
                        final String relatifSourcePath = StringUtils.substringAfter(
                                source.toString(), folderToCompress.getPath());

                        final TarArchiveEntry entry = new TarArchiveEntry(
                                source.toFile(), relatifSourcePath);

                        try (InputStream in = new FileInputStream(source.toFile())){
                            out.putArchiveEntry(entry);

                            IOUtils.copy(in, out);

                            out.closeArchiveEntry();
                        }
                        catch (IOException e) {
                            // Handle this better than bellow...
                            throw new RuntimeException(e);
                        }
                    }
                });

    }

    return tarFile;
}
_
1
pierrefevrier

パスに関連して機能させるには、@ merrickソリューションにいくつかの調整を加える必要がありました。おそらく、最新のMaven依存関係があります。現在受け入れられている解決策は私にはうまくいきませんでした。

import Java.io.BufferedOutputStream;
import Java.io.File;
import Java.io.FileInputStream;
import Java.io.FileNotFoundException;
import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.util.ArrayList;
import Java.util.List;
import org.Apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.Apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.Apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.Apache.commons.io.FileUtils;
import org.Apache.commons.io.IOUtils;
import org.Apache.commons.io.filefilter.DirectoryFileFilter;
import org.Apache.commons.io.filefilter.RegexFileFilter;

public class TAR {

    public static void CreateTarGZ(String inputDirectoryPath, String outputPath) throws IOException {

        File inputFile = new File(inputDirectoryPath);
        File outputFile = new File(outputPath);

        try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                GzipCompressorOutputStream gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream);
                TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(gzipOutputStream)) {

            tarArchiveOutputStream.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
            tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);

            List<File> files = new ArrayList<>(FileUtils.listFiles(
                    inputFile,
                    new RegexFileFilter("^(.*?)"),
                    DirectoryFileFilter.DIRECTORY
            ));

            for (int i = 0; i < files.size(); i++) {
                File currentFile = files.get(i);

                String relativeFilePath = inputFile.toURI().relativize(
                        new File(currentFile.getAbsolutePath()).toURI()).getPath();

                TarArchiveEntry tarEntry = new TarArchiveEntry(currentFile, relativeFilePath);
                tarEntry.setSize(currentFile.length());

                tarArchiveOutputStream.putArchiveEntry(tarEntry);
                tarArchiveOutputStream.write(IOUtils.toByteArray(new FileInputStream(currentFile)));
                tarArchiveOutputStream.closeArchiveEntry();
            }
            tarArchiveOutputStream.close();
        }
    }
}

Maven

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

        <dependency>
            <groupId>org.Apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.18</version>
        </dependency>
0
conteh