读取压缩包里的文件的数据
例:test.zip里面有两个excel表格,现需要获得表格中的数据。
大概思路就是,zip== =》zipInputstream== =》zipEntry。zipEntry实际上就是读到的压缩包内的文件。java.util包含zip相关的工具类,仅支持zip类型压缩包,其他类型的压缩包就需要导入依赖;个人建议使用apache的工具类。
常用的压缩包一般是zip、7z、rar,但是rar5的压缩算法并没有开源,目前没有什么第三方组件能对rar进行相关的操作 。
真的想要对rar进行操作的话,我觉得可以通过java调用dos或shell命令以电脑下载的压缩软件进行操作。
以项目前端上传文件为例
zip java.util
java.util几乎只能对zip进行操作,我也建议使用zip类型的压缩包
此代码后续需要将zipEntry转为inputStream操作,需要调用zipFile的getInputStream方法,所以需要创建zipFile的对象。
PS:生成临时file或者拷贝file这个操作并不是必须的,主要看业务需求。下面的代码是读取excel文件中的数据,读取xls是会出现Stream closed。如果不生成新的文件时可直接对zipInputStream操作
@PostMapping("/java/upload")
// 此处用的是MultipartFile来接收前端上传的压缩包
public void compressUpload(MultipartFile multipartFile) throws IOException {
// 后续需要将zipEntry转为inputStream操作,需要zipFile的getInputStream方法
// 这里copy文件和创建临时文件的原因都是相同的
// File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));
// // 使用copy会在指定位置生成一个文件
// FileCopyUtils.copy(multipartFile.getBytes(), file);
// 使用临时文件的话,这行必须要写在transferTo方法上边
ZipInputStream zipInputStream = new ZipInputStream(multipartFile.getInputStream());
// 使用临时文件则会在c盘中的temp生成临时的文件
File file = File.createTempFile("temp", ".zip");
multipartFile.transferTo(file);
System.out.println(file.getName());
// 创建zipFile
ZipFile zipFile = new ZipFile(file);
ZipEntry zipEntry;
// 读取压缩包内的文件为zipEntry
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
System.out.println("zipEntry:" + zipEntry);
if (zipEntry.isDirectory()) {
continue;
}// 是否为文件夹
long size = zipEntry.getSize();
System.out.println(zipEntry.getName() + "-" + size + "字节");
if (size > 0) {
// 使用zipFile.getInputStream(),则需要关闭zipFile,即zipFile.close()才能删除临时文件
// 此方法为自己封装读取excel文件的工具类的,根据你的业务需求调整
ReadExcelUtil.readExcel(zipEntry.getName(), zipFile.getInputStream(zipEntry), 0);
}
System.out.println("--------------------");
}
zipInputStream.closeEntry();
// 关闭zipFile 关闭对应的流
zipInputStream.close();
zipFile.close();
// 执行时删除,删除刚刚创建的临时文件
System.out.println(file.delete());
}
zip apache.commons
apache.commons.compress中有压缩包通用的类;
个人建议:如果是读取压缩包内文件的操作不要使用通用类,会有很多奇怪的bug;如果是对压缩包解压或者对文件进行压缩的操作可以考虑使用通用的类
导入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.23.0</version>
</dependency>
大概内容和上边类似,Apache的zip相关的类方法和java.util是存在差异的。Apache的zipArchiveInputStream获取的zipArchiveEntry作为参数的话,zipFile.getInputStream会返回null,就是说无法通过此方法获得对应的zipArchiveEntry,所以不能使用zipArchiveInputStream获得zipArchiveEntry。
注:此处的zipFile是Apache的并非java.util,同样这里生成临时文件也是为了规避一下不必要的问题(压缩包内有多个同名文件,比如一个test.zip里面是test.xls和test.xlsx,会出现只能读取到一个文件)
@PostMapping("/compress/zip")
// 此处用的是MultipartFile来接收前端上传的压缩包
public void compressZip(MultipartFile multipartFile) throws IOException {
File file = File.createTempFile("temp", ".zip");
multipartFile.transferTo(file);
System.out.println(file.getName());
ZipFile zipFile = new ZipFile(file);
// apache的zipfile的getEntries可直接获得对应的entry
// 此处用的是不含参的getEntries获得压缩包内所有的文件,根据你的需求使用含参的方法获取指定文件的entry
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
ZipArchiveEntry zipArchiveEntry;
while (entries.hasMoreElements()) {
zipArchiveEntry = entries.nextElement();
System.out.println("archiveEntry:" + zipArchiveEntry);
if (zipArchiveEntry.isDirectory()) {
continue;
}
long size = zipArchiveEntry.getSize();
System.out.println(zipArchiveEntry.getName() + ":" + size);
if (size > 0) {
InputStream inputStream = zipFile.getInputStream(zipArchiveEntry);
// 此方法为自己封装读取excel文件的工具类的,根据你的业务需求调整
ReadExcelUtil.readExcel(zipArchiveEntry.getName(), inputStream, 0);
inputStream.close();
}
System.out.println("--------------------");
}
// 关闭对应文件,删除生成的临时文件
zipFile.close();
System.out.println(file.delete());
}
下面是使用apache的方法,不生成file的代码
@PostMapping("/compress/zip")
public void compressZip(MultipartFile multipartFile) throws IOException {
System.err.println("filename:" + multipartFile.getOriginalFilename());
System.out.println("--------------------");
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(multipartFile.getInputStream());
ZipArchiveEntry zipArchiveEntry;
while ((zipArchiveEntry = zipArchiveInputStream.getNextZipEntry()) != null) {
System.out.println("archiveEntry:" + zipArchiveEntry);
if (zipArchiveEntry.isDirectory()) {
continue;
}
long size = zipArchiveEntry.getSize();
System.out.println(zipArchiveEntry.getName() + ":" + size);
if (size > 0) {
ReadExcelUtil.readExcel(zipArchiveEntry.getName(), zipArchiveInputStream, 0);
}
System.out.println("--------------------");
}
System.out.println("********************");
zipArchiveInputStream.close();
}
7z
java.util不支持,使用apache.common.compress
需要导入对应依赖
读取7z的大概流程很容易读懂,要注意的是:apache的7z工具类里面没SevenZInputStream,业务需要的话,可调用SevenZFlie中的方法来获得对应的InputStream
@PostMapping("/compress/7z")
public void compress7z(MultipartFile multipartFile) throws IOException {
System.err.println("filename:" + multipartFile.getOriginalFilename());
File file = File.createTempFile("temp", ".7z");
multipartFile.transferTo(file);
// SevenZFile sevenZFile = new SevenZFile(new File(fileName));
SevenZFile sevenZFile = new SevenZFile(file);
System.out.println(file.getName());
SevenZArchiveEntry sevenZArchiveEntry;
while ((sevenZArchiveEntry = sevenZFile.getNextEntry()) != null) {
if (!sevenZArchiveEntry.isDirectory()) {
long size = sevenZArchiveEntry.getSize();
System.out.println(sevenZArchiveEntry.getName() + ":" + size);
if (size > 0) {
ReadExcelUtil.readExcel(sevenZArchiveEntry.getName(), sevenZFile.getInputStream(sevenZArchiveEntry), 0);
}
}
}
sevenZFile.close();
System.out.println(file.delete());
}
apache.common.compress中还有其他格式压缩包的工具类,具体使用与上方这两种类似。
eg:有更好的方法或者有问题可留言