ZipOutputStream
实现文件的压缩类
ZipOutputStream(OutputStream out) 创建新的zip输出流
void putNextEntry(ZipEntry e) ZipOutputStream类的方法开始写入新的zip文件条目并将流定位到条目数据的开始处
ZipEntry(String name) ZipEntry类的构造使用指定名称创建新的zip条目,如test/mm.jpg,test/gg.jpg
ZipInputStream
实现文件的解压类
ZipInputStream(InputStream in) 创建新的zip输入流
ZipEntry getNextEntry() ZipInputStream类的方法getNextEntry返回ZipEntry类型读取下一个zip文件条目并将流定位到该条目数据的开始处
import java.io.BufferedInputStream;
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.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class CompressAndDemopressDemo {
public static void main(String[] args) {
//compress("E:\\Java_IO\\hudechao.zip",new File("E:\\Java_IO\\hudechao"));
decompress("E:\\Java_IO\\hudechao.zip","E:\\Java_IO\\hudechao2");
}
//文件压缩,参数zipFileName表示压缩后的压缩名称,targetFile表示需要被要锁的源文件
public static void compress(String zipFileName,File targetFile) {
try {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFileName)); //实现压缩
BufferedOutputStream bos = new BufferedOutputStream(zos); //压缩文件的输出流
zip(bos,zos,targetFile,targetFile.getName()); //所以实现压缩的实际方法都需要这两个参数,zos,bos,targetFile.getName()是为了获取每个条目的唯一路径ZipEntry
bos.close();
zos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void zip(BufferedOutputStream bos, ZipOutputStream zous, File targetFile, String name) throws IOException {
if(targetFile.isDirectory()) { //如果需要被压缩的源文件是个目录时,需要对里面的每个文件生成条目-ZipEntry()
File[] files = targetFile.listFiles();
if(files.length==0) { //如果是个空目录时,就直接生成一个条目-ZipEntry()
zous.putNextEntry(new ZipEntry(name+"/")); //这里name是被压缩的文件的名称,为什么带上“/”,因为windows里目录文件后面会跟"/"
}
for(File f:files) { //如果是个目录且目录里有文件,就要递归判断里面的文件是目录还是文件
zip(bos,zous,f,name+"/"+f.getName()); //这里 name+"/"+f.getName() 就如同 test/mm.jpg,所以"/" 是有必要的;在把 name+"/"+f.getName()当做name作为参数递归调用
}
}else {
zous.putNextEntry(new ZipEntry(name)); //这里的name是:1、本身传入的参数name就是个文件不是目录,2、当是目录时,经过递归调用时的 name+"/"+f.getName()
InputStream in = new FileInputStream(targetFile);
BufferedInputStream bis = new BufferedInputStream(in);
int len = -1;
byte[] bytes = new byte[1024];
while((len=bis.read(bytes))!=-1) {
bos.write(bytes,0,len);
}
bis.close();
}
}
/**
* ?不能对在windows里手动压缩的zip包进行解压?
* 文件的解压
* 如下方法只能对压缩包里的是非空目录才能解压
*/
public static void decompress(String targetFileName,String parent) { //参数targetFileName表示需要解压的源文件,parent表示解压到该目录下
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(targetFileName)); //解压文件的输入流
ZipEntry entry = null;
File file = null;
while((entry=zis.getNextEntry())!=null && !entry.isDirectory()) { //循环的条件是:待解压文件的里面的条目不为空,且条目是个文件时
file = new File(parent,entry.getName()); //当该条目是文件时就对该文件创建File,参数时它的父目录和自己本身的名称如(test,mm,jpg),所以它的路径是test/mm.jpg
if(!file.exists()) {
new File(file.getParent()).mkdirs(); //这里判断file是否存在,解压的时候file(包括文件和目录)一般肯定是在新目录里不存在的,
//所以它的上级目录时肯定要在的,所以就必须得先创建它的上级目录;然后流才会自动在该创建好的上级目录里创建File
}
OutputStream out = new FileOutputStream(file);//解压后的输出流,bytes数组里的条目值写入file里
BufferedOutputStream bos = new BufferedOutputStream(out);
int len = -1;
byte[] bytes = new byte[1024];
while((len=zis.read(bytes))!=-1) { //先由解压输入流读进来每个条目,读进bytes数据存储
bos.write(bytes,0,len); //再由解压输出流写出去
}
bos.close();
System.out.println(file+"解压成功");
}
zis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 文件的解压
* 1、对于压缩包里是空目录的也可解压;
* 2、对于压缩包里即有目录又有文件的也可解压;
*/
public static void decompress2(String targetFileName,String parent) { //targetFileName表示待解压的文件,parent表示解压后存在目录的父级目录
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(targetFileName));
BufferedInputStream bis = new BufferedInputStream(zis);
ZipEntry entry = null;
while((entry=zis.getNextEntry())!=null) { //首先条目不能为空才能解压的即表示压缩包里是有东西存在的;如果为空那么说明这个压缩包格式是异常的
if(entry.isDirectory()) { //如果条目是个目录,那么直接创建这个目录,就表示解压了这个压缩包了
File file = new File(parent,entry.getName()); //当该条目是文件时就对该文件创建File,参数时它的父目录和自己本身的名称如(test,mm,jpg),所以它的路径是test/mm.jpg
file.mkdirs();
System.out.println(file+"解压完成");
}else {
File files = new File(parent,entry.getName()); //如果不是个目录,即是个文件的话,那么就要创建File类的对象了
if(!files.exists()) { //解压的文件一般肯定事先不存在的
new File(files.getParent()).mkdirs(); //所以得先创建它的父级目录,因为它是个文件,那么它的父级一定是个目录了(只有目录里才能存文件的嘛);然后流才会自动在该创建好的上级目录里创建File
}
OutputStream ous = new FileOutputStream(files);//这里的输出流是经上面文件的父目录创建完成后,才会去执行,所以是跟上面的if(!files.exists())是串行的,只有先创建了目录,才能在该目录里创建文件流
BufferedOutputStream bos = new BufferedOutputStream(ous); //所以不是在else的语句里,如果是else语句里,那么程序就不会执行到该代码了,因为else判断存在时才会执行
int len = -1;
byte[] bytes = new byte[1024];
while((len=bis.read(bytes))!=-1) {
bos.write(bytes,0,len);
}
bos.close();
System.out.println(files+"解压完成");
}
}
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}