关于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
答案是肯定。