压缩流
在日常中经常会使用到像WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行压缩以方便传输。
在JAVA中,为了减少传输时的数据量也提供了专门的压缩流,可以将文件或文件夹压缩成 ZIP、JAR、GZIP等文件的格式。
压缩流的实现:正常情况下在IO操作中,所有的类库都是在io包中。
在JAVA IO中,不仅可以实现ZIP压缩格式的输入、输出,也可以实现ZIP、JAR及GZIP文件格式的压缩:
JAR压缩的支持类保存在java.util.jar包中,常用的类有如下几个: JAR压缩输出流:JarOutputStream JAR压缩输入流:JarInputStream JAR文件:JARFile JAR实体:JAREntry
GZIP是用于UNIX系统的文件压缩,在Linux中经常会使用到*.gz的文件,就是GZIP格式,GZIP压缩的支持类保存在java.util.zip包中,常用的类有如下几个: GZIP压缩输出流:GZIPOutputStream GZIP压缩输入流:GZIPInputStream
ZIP是一种较为常见的压缩形式,在Java中要想实现ZIP的压缩需要导入java.util.zip包,可以使用此包中的ZipFile、ZipOutputStream、ZipInputStream、ZipEntry几个类完成。
1、ZipOutputStream类
ZipOutputStream是OutputStream的子类,该类实现了以ZIP文件格式写入文件的输出流过滤器。 包括对压缩和未压缩条目的支持。
-
-
void
putNextEntry(ZipEntry e)
开始编写新的ZIP文件条目,并将流定位到条目数据的开头。
void
setComment(String comment)
设置ZIP文件注释。
-
ZipInputStream是InputStream的子类,该类实现了以ZIP文件格式读取文件的输入流过滤器。 包括对压缩和未压缩条目的支持。
-
-
protected ZipEntry
createZipEntry(String name)
为指定的条目名称创建一个新的
ZipEntry
对象。ZipEntry
getNextEntry()
读取下一个ZIP文件条目,并将流定位在条目数据的开头。如果没有更多条目,则为null
-
在Java中,ZipFile是一个专门表示zip压缩文件(.zip)的类,每一个压缩文件都可以使用 ZipFile表示,还可以使用 ZipFile根据压缩后的文件名找到每一个压缩文件中的ZipEntry对象并将其进行解压缩操作。
ZipFile在实例化的时候必须接收File类的实例,此File类的实例是指向一个压缩的*.zip文件。
-
-
ZipFile(File file)
打开一个ZIP文件,读取指定的File对象。
ZipFile(String name)
打开一个zip文件进行阅读。
-
-
-
void
close()
关闭ZIP文件。
String
getComment()
返回zip文件注释,否则返回null。
ZipEntry
getEntry(String name)
返回指定名称的zip文件条目,如果找不到则返回null。
InputStream
getInputStream(ZipEntry entry)
返回用于读取指定zip文件条目内容的输入流。
String
getName()
返回ZIP文件的路径名。
-
在Java中,每一个压缩文件(.zip)中都会存在多个子文件,那么每一个子文件使用ZipEntry对象表示。可以获取到文件条目的数据大小,条目名称等文件条目信息
ZipEntry在实例化的时候必须要设置名称,此名称实际上就是压缩文件中的每一个文件条目的名称。
-
-
ZipEntry(String name)
创建具有指定名称的新的zip条目。
-
-
-
String
getComment()
返回条目的注释字符串。
long
getCrc()
返回未压缩条目数据的CRC-32校验和。
String
getName()
返回条目的名称。
long
getSize()
返回条目数据的未压缩大小。
long
getTime()
返回条目的最后修改时间。
void
setTime(long time)
设置条目的最后修改时间。
-
包含三个方法:
1、压缩一个文件
2、压缩一个文件夹(嵌套或不嵌套都可以)
1)递归实现嵌套文件或不嵌套文件夹的压缩
对一个文件夹进行压缩,例如,现在在某盘存在一个a文件夹。从使用各种压缩软件的经验来看,如果现在要进行压缩的话,则在压缩之后的文件中应该存在一个a文件夹。在文件夹中应该存放着各个压缩文件。所以在实现的时候就应该列出文件夹中的全部内容,并把每一个内容设置成ZipEntry的对象,保存到压缩文件之中。
3、解压zip文件(里面嵌套或不嵌套都可以)到指定目录下
直接上代码
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class ZipUtil {
private ZipUtil(){}
/**
* 压缩一个文件
*
* @param file 要压缩的文件
* @param zipFile 压缩后的zip文件
* @return boolean true-压缩成功,false-压缩失败
*/
public static boolean zipOneFile(File file, File zipFile) {
try (
InputStream input = new FileInputStream(file);
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
) {
// 压缩读写之前必须通过putNextEntry设置一个ZipEntry对象(表示ZIP文件条目)
zipOut.putNextEntry(new ZipEntry(file.getName()));
//zipOut.setComment("UTF-8"); // 设置ZIP文件注释
byte[] buffer = new byte[2048];
int len = -1;
while ((len = input.read(buffer)) != -1) {
zipOut.write(buffer, 0, len);
}
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* 压缩一个文件夹(嵌套或不嵌套都可以)
*
* @param fileDir 要压缩的文件夹
* @param zipFile 压缩后的zip文件
* @return boolean true-压缩成功,false-压缩失败
*/
public static boolean zipFileDir(File fileDir, File zipFile) {
// 检查目录是否存在,不存在时创建
if (!fileDir.isDirectory()) {
fileDir.mkdirs();
}
try (
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
) {
File[] files = fileDir.listFiles();
for (File fileSrc : files) {
recursionZip(fileSrc, zipOut, fileDir.getName());
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 递归实现文件或文件夹的压缩
*
* @param file 要压缩的文件或目录
* @param zipOut 压缩后的zip文件输出流
* @param filePath 要压缩的文件路径或目录路径(最后不带/)
* @throws Exception
*/
private static void recursionZip(File file, ZipOutputStream zipOut, String filePath) throws Exception {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File fileSrc : files) {
recursionZip(fileSrc, zipOut, filePath + File.separator + file.getName());
}
} else {
InputStream input = new FileInputStream(file);
zipOut.putNextEntry(new ZipEntry(filePath + File.separator + file.getName()));
byte[] buffer = new byte[2048];
int len = -1;
while ((len = input.read(buffer)) != -1) {
zipOut.write(buffer, 0, len);
}
input.close();
}
}
/**
* 解压zip文件(里面嵌套或不嵌套都可以)到指目录下
*
* @param file:需要解压的zip文件
* @param destDir:将zip文件解压到某个路径下(最后不带/)
* @throws Exception
*/
public static void unZipFile(File file, String destDir) throws Exception {
ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file)); // 实例化压缩输入流
ZipFile zipFile = new ZipFile(file); // 实例化ZipFile对象
ZipEntry zipEntry = null;
File outFile = null;
OutputStream out = null;
InputStream input = null;
try {
while ((zipEntry = zipInput.getNextEntry()) != null) {
//System.out.println("解压文件: " + zipEntry.getName()); // 解压文件: file01\1.png
outFile = new File(destDir + File.separator + zipEntry.getName());
if(zipEntry.isDirectory()){
outFile.delete();
outFile.mkdirs();
continue;
}
if (outFile.exists()) {
outFile.delete();
}else{
outFile.createNewFile();
}
input = zipFile.getInputStream(zipEntry); // 得到每一个压缩实体对象的输入流
out = new FileOutputStream(outFile); // 实例化文件输出流
byte[] buffer = new byte[2048];
int len = -1;
while ((len = input.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
} finally {
if (zipInput != null) zipInput.close();
if (out != null) out.close();
if (input != null) input.close();
if (zipFile != null) zipFile.close();
}
}
public static void main(String[] args) {
// File file = new File("E:/java/text.txt");
// File zipFile = new File("E:/java/text.zip");
// boolean flag = ZipUtil.zipOneFile(file, zipFile);
// System.out.println(flag);
// File fileDir = new File("E:/java/file01");
// File zipFile = new File("E:/java/file01.zip");
// boolean flag = ZipUtil.zipFileDir(fileDir,zipFile);
// System.out.println(flag);
File zipFile = new File("E:/java/file01.zip");
try {
ZipUtil.unZipFile(zipFile, "E:/java/unzip");
} catch (Exception e) {
e.printStackTrace();
}
}
}
本人亲测OK,但是解压只能是xx.zip文件下只能是一个文件夹条目,它里面嵌套包含ok,
有时我们可能拿到的是文件的 二进制数据,通过二进制流包装一一下,就可以了。比如:
@PostMapping("/upload")
@ResponseBody
public String upload(MultipartFile file) {
try (
ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));
) {
ZipEntry zipEntry = null;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
if (zipEntry.isDirectory()) {
System.out.println("==目录==" + zipEntry.getName());
} else {
System.out.println("==文件==" + zipEntry.getName());
}
}
} catch (IOException e) {
e.printStackTrace();
return "error";
}
return "success";
}
@GetMapping("/download")
public ResponseEntity download() {
List bytesFileItemList = getBytesFileItemList();
try (
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(byteArrayOut);
) {
ZipEntry zipEntry = null;
for (BytesFileItem fileItem : bytesFileItemList) {
zipEntry = new ZipEntry(fileItem.getName());
zipEntry.setSize(fileItem.getContent().length);
zipOut.putNextEntry(zipEntry);
zipOut.write(fileItem.getContent());
}
zipOut.close();
String downloadFilenName = "下载嵌套zip文件.zip";
HttpHeaders headers = new HttpHeaders();
String downloadFileName = new String(downloadFilenName.getBytes("UTF-8"), "iso-8859-1");
headers.setContentDispositionFormData("attachment", downloadFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity(byteArrayOut.toByteArray(), headers, HttpStatus.CREATED);
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok(new byte[0]);
}
//模拟下载嵌套文件
public List getBytesFileItemList() {
List list = new ArrayList();
for (int i = 1; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?