关于TarArchiveOutputStream输出Tar中包含

2019-12-12  本文已影响0人  Pasca

遇到使用TarArchiveEntry的来输出tar文件,发现会带入文件的目录。解决办法就是指定这个文件的文件名称(注意:文件名称不带反斜杠这种文件层级保留字符)就可以解决问题。

TarArchiveEntry tae = new TarArchiveEntry(file, file.getName());

想要看具体思路的可以往下读,不想的就可以走了。

今天做Java将若干个文件归档为tar时。使用了org.apache.commons:commons-compress:1.19,下面是代码:

/**
     * @param files   文件列表
     * @param tarFile 输出文件
     * @return void
     * @author Benjamin
     * @description [**将列表文件归档成Tar包**]
     * @date 15:09 2019/12/12
     * @version 1.0
     **/
    public static void tarArchiveFiles(List<File> files, File tarFile) throws IOException {
        TarArchiveOutputStream taos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
        System.out.println("目标Tar文件:" + tarFile.getPath());
        for (File off : files) {
            System.out.println("将要加入的文件:" + off.getPath());
            FileInputStream fis = new FileInputStream(off);
            TarArchiveEntry tae = new TarArchiveEntry(off);
            tae.setSize(off.length());
            taos.putArchiveEntry(tae);
            IOUtils.copy(fis, taos);
            fis.close();
            taos.flush();
            taos.closeArchiveEntry();
        }
        taos.close();
    }

运行结果:


image.png

然后解压出来的文件:


image.png
可以看到,第一个文件他把文件的父路径一起打包进去了。然而我们这边的业务要求是不打包父路径。找遍了他的方法都没看到怎么设置不打包父路径的代码。度娘了半天也没看到。(全是粘贴复制)
静下心来,看了看源码,突然发现有这样的代码:
//gou构造方法,我调用的是这个方法
public TarArchiveEntry(File file) {
        //获取了当前文件的路径,来作为文件名
        this(file, file.getPath());
    }
    //最终都是调用这个构造方法
    public TarArchiveEntry(File file, String fileName) {
        this.name = "";
        this.userId = 0L;
        this.groupId = 0L;
        this.size = 0L;
        this.linkName = "";
        this.magic = "ustar\u0000";
        this.version = "00";
        this.groupName = "";
        this.devMajor = 0;
        this.devMinor = 0;
        this.extraPaxHeaders = new HashMap();
        String normalizedName = normalizeFileName(fileName, false);
        ....略...
    }

从上面可以看到,当我们创建TarArchiveEntry对象的时候,如果不传入文件名称,他就会使用当前文件的路径作为名称。在tar文件中,你的文件就是/xxx/xxx/xxx/xxx.jpg。当你解压的时候/xxx/xxx/xxx/就会变为文件夹。于是乎,开始实验。直接TarArchiveEntry(File file, String fileName) 来指定不含路径 的名称。

/**
     * @param files   文件列表
     * @param tarFile 输出文件
     * @return void
     * @author Benjamin
     * @description [**将列表文件归档成Tar包**]
     * @date 15:09 2019/12/12
     * @version 1.0
     **/
    public static void tarArchiveFiles(List<File> files, File tarFile) throws IOException {
        TarArchiveOutputStream taos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
        System.out.println("目标Tar文件:" + tarFile.getPath());
        for (File off : files) {
            System.out.println("将要加入的文件:" + off.getPath());
            FileInputStream fis = new FileInputStream(off);
            TarArchiveEntry tae = new TarArchiveEntry(off, off.getName());
            tae.setSize(off.length());
            taos.putArchiveEntry(tae);
            IOUtils.copy(fis, taos);
            fis.close();
            taos.flush();
            taos.closeArchiveEntry();
        }
        taos.close();
    }
image.png
image.png
可以看到,已经没有上级文件夹了。于是这个问题就解决了。
如果不想带有路径,则调用TarArchiveEntry(File file, String fileName) l来为文件指定一个名称
扩展一下,既然他是根据文件名称来解压,我们是不是也可以在文件名称前面加上文件夹的名称,来达到自定义里面的文件层级呢?
/**
     * @param files   文件列表
     * @param tarFile 输出文件
     * @return void
     * @author Benjamin
     * @description [**将列表文件归档成Tar包**]
     * @date 15:09 2019/12/12
     * @version 1.0
     **/
    public static void tarArchiveFiles(List<File> files, File tarFile) throws IOException {
        TarArchiveOutputStream taos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
        System.out.println("目标Tar文件:" + tarFile.getPath());
        for (File off : files) {
            System.out.println("将要加入的文件:" + off.getPath());
            FileInputStream fis = new FileInputStream(off);
            TarArchiveEntry tae = new TarArchiveEntry(off, "新建文件夹" + File.separator + off.getName());
            tae.setSize(off.length());
            taos.putArchiveEntry(tae);
            IOUtils.copy(fis, taos);
            fis.close();
            taos.flush();
            taos.closeArchiveEntry();
        }
        taos.close();
    }
image.png

答案是肯定。

上一篇下一篇

猜你喜欢

热点阅读