package javaFileStudy;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* 文件较复杂操作: 打包、解压
*
* 目标
* 1、使用java.util.zip.ZipOutputStream 进行压缩 (压缩单个文件、单个文件夹(全文件或目录文件)、多个文件)
* 2、使用java.util.zip.ZipInputStream 进行解压
* 3、使用org.apache.tools.zipZipOutputStream 进行压缩,并了解他是如何解决java.util.zip.ZipOutputStream压缩后文件名乱码的
* 答:jdk1.7就自带编码指定,解决乱码。new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"))
*
* 知识科普 :
* 1、压缩包:相当于 ZipEntry的容器
* 2、压缩:使用java.util.zip.ZipOutputStream(目标文件输出流).putZipEntry(),向zip文件中创建ZipEntry,然后写入数据(类似Map.put)
* 3、解压:依次取出zip文件中的ZipEntry内容写入到新的文件中
* 4、在java处理中,一般把文件创建在临时目录中System.getPorperty("java.io")中进行使用,服务器重启就没了。
*
* @author xubo
*
*/
public class File2 {
public static void main(String args[]) throws IOException {
// String filepath = "second/three/second/File.txt";
// String zipFilepath = "second/zipFile.zip"; // 必须正确文件路径,因为打包里面没有进行判断。 创建文件使用File1.create就可以随意了
// compressFile(new File(filepath), new File(zipFilepath));
// 再将"second下的所有文件进行压缩到first下面" (建议自己拼的路径用下面的方式创建文件)
compressFile(Paths.get("second").toFile(), Paths.get("first/second.zip").toFile());
// 再测试压缩多个文件 , 直接写文件,那么应该不存在文件夹
/*
* File file1 = Paths.get("second/three/second/File.txt").toFile();
* File file2 = Paths.get("second/zipFile.zip").toFile();
* File zipFile = Paths.get("first/second2.zip").toFile();
* File[] files = new File[2];
* files[0] = file1;
* files[1] = file2;
* compressFiles(files, zipFile);
*/
// 将刚压缩的文件解压到"three"
File zipFile = Paths.get("first/second.zip").toFile();
decompressFile(zipFile, "three2");
}
/**
* java.util.zip.ZipOutputStream压缩单个文件
*
* @throws IOException
*
*/
static File compressFile(File file, File zipFile) throws IOException {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile)); // 构建Zip输出流
compressSingeFile(file, zos);
zos.flush();
zos.close(); // 不需要指明ZOS关闭,因为包装流关闭,内部流也会关闭。
return zipFile;
}
/**
* 压缩单个文件单独处理
* zos请自行flush()和close()处理
*
* @throws IOException
*/
private static void compressSingeFile(File file, ZipOutputStream zos) throws IOException {
compressSingeFile(file, zos, null);
}
/**
* 压缩单个文件单独处理,供循环调用
*
* @param file
* 原来的文件
* @param zos
* zipFile的输出流
* @param separatePosition
* 文件绝对路径需要截断的位置,用来保存文件名称
* @throws IOException
*/
private static void compressSingeFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
separatePosition = separatePosition == null ? (file.getAbsolutePath().lastIndexOf(File.separator) + 1) : separatePosition;// 初始化路径隔断
if (file.isFile()) { // 是个正常文件,不是目录
compressNormalFile(file, zos, separatePosition);
} else if (file.listFiles().length == 0) { // 空文件夹
// compressEmptyDirectory(file, zos, separatePosition); 这个不行,被网上的某高手骗了
} else { // 含有内容的文件夹,循环处理
File[] files = file.listFiles();
if (files != null && files.length > 0) { // 空文件夹暂时不处理
for (File sf : files) {
compressSingeFile(sf, zos, separatePosition);
}
}
}
}
/**
* 压缩一个正常文件
*
* @param file
* @param zos
* @param separatePosition
* @throws IOException
*/
private static void compressNormalFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
String entryPath = file.getAbsolutePath().substring(separatePosition);
compressToPointedZipEnrty(file, zos, entryPath);
}
/**
* 压缩一个空文件夹
*
* @param file
* @param zos
* @param separatePosition
* @throws IOException
*/
private static void compressEmptyDirectory(File file, ZipOutputStream zos, Integer separatePosition) throws IOException { // 压缩空文件夹
String entryPath = file.getAbsolutePath().substring(separatePosition) + File.separator;
compressToPointedZipEnrty(file, zos, entryPath);
}
/**
* 压缩文件到一个指定名称的zipEntry
*
* @param file
* @param zos
* @param zipEntryName
* @throws IOException
*/
private static void compressToPointedZipEnrty(File file, ZipOutputStream zos, String zipEntryName) throws IOException { // 压缩空文件夹
FileInputStream fis = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(zipEntryName));
byte[] b = new byte[2000];
int tmp = 0;
if ((tmp = fis.read(b)) != -1) {
zos.write(b, 0, tmp);
}
fis.close(); // 哪里创建的流哪里关闭
}
/**
* java.util.zip.ZipOutputStream压缩多个文件
*
* @throws IOException
*/
static File compressFiles(File[] files, File zipFile) throws IOException {
if (files.length > 0) {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"));
for (File file : files) {
compressSingeFile(file, zos);
}
zos.flush();
zos.close();
}
return zipFile;
}
/**
* 解压文件到目录directoryPath下面
*
* @param file
* @param directoryPath
* @return
* @throws IOException
*/
static List<File> decompressFile(File zipFile, String directoryPath) throws IOException {
List<File> result = new ArrayList<File>();
File directory = new File(directoryPath);
if (!directory.exists()) { // 目录不存在
directory.mkdirs();
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry zipEntry = null;
while ((zipEntry = zis.getNextEntry()) != null) { // 便利zipFile中的zipEntry
File sFile = new File(directory.getAbsolutePath() + File.separator + zipEntry.getName());
System.out.println(zipEntry.getName());
// 这有个坑,如果是多层文件夹嵌套可能文件路径不存在,得校验
if (!sFile.getParentFile().exists()) {
sFile.getParentFile().mkdirs();
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
byte[] b = new byte[2000];
int tmp = 0;
while ((tmp = zis.read(b)) != -1) {
bos.write(b, 0, tmp);
}
bos.flush();
bos.close();
zis.closeEntry();
result.add(sFile);
}
zis.close();
return result;
}
}
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* 文件较复杂操作: 打包、解压
*
* 目标
* 1、使用java.util.zip.ZipOutputStream 进行压缩 (压缩单个文件、单个文件夹(全文件或目录文件)、多个文件)
* 2、使用java.util.zip.ZipInputStream 进行解压
* 3、使用org.apache.tools.zipZipOutputStream 进行压缩,并了解他是如何解决java.util.zip.ZipOutputStream压缩后文件名乱码的
* 答:jdk1.7就自带编码指定,解决乱码。new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"))
*
* 知识科普 :
* 1、压缩包:相当于 ZipEntry的容器
* 2、压缩:使用java.util.zip.ZipOutputStream(目标文件输出流).putZipEntry(),向zip文件中创建ZipEntry,然后写入数据(类似Map.put)
* 3、解压:依次取出zip文件中的ZipEntry内容写入到新的文件中
* 4、在java处理中,一般把文件创建在临时目录中System.getPorperty("java.io")中进行使用,服务器重启就没了。
*
* @author xubo
*
*/
public class File2 {
public static void main(String args[]) throws IOException {
// String filepath = "second/three/second/File.txt";
// String zipFilepath = "second/zipFile.zip"; // 必须正确文件路径,因为打包里面没有进行判断。 创建文件使用File1.create就可以随意了
// compressFile(new File(filepath), new File(zipFilepath));
// 再将"second下的所有文件进行压缩到first下面" (建议自己拼的路径用下面的方式创建文件)
compressFile(Paths.get("second").toFile(), Paths.get("first/second.zip").toFile());
// 再测试压缩多个文件 , 直接写文件,那么应该不存在文件夹
/*
* File file1 = Paths.get("second/three/second/File.txt").toFile();
* File file2 = Paths.get("second/zipFile.zip").toFile();
* File zipFile = Paths.get("first/second2.zip").toFile();
* File[] files = new File[2];
* files[0] = file1;
* files[1] = file2;
* compressFiles(files, zipFile);
*/
// 将刚压缩的文件解压到"three"
File zipFile = Paths.get("first/second.zip").toFile();
decompressFile(zipFile, "three2");
}
/**
* java.util.zip.ZipOutputStream压缩单个文件
*
* @throws IOException
*
*/
static File compressFile(File file, File zipFile) throws IOException {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile)); // 构建Zip输出流
compressSingeFile(file, zos);
zos.flush();
zos.close(); // 不需要指明ZOS关闭,因为包装流关闭,内部流也会关闭。
return zipFile;
}
/**
* 压缩单个文件单独处理
* zos请自行flush()和close()处理
*
* @throws IOException
*/
private static void compressSingeFile(File file, ZipOutputStream zos) throws IOException {
compressSingeFile(file, zos, null);
}
/**
* 压缩单个文件单独处理,供循环调用
*
* @param file
* 原来的文件
* @param zos
* zipFile的输出流
* @param separatePosition
* 文件绝对路径需要截断的位置,用来保存文件名称
* @throws IOException
*/
private static void compressSingeFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
separatePosition = separatePosition == null ? (file.getAbsolutePath().lastIndexOf(File.separator) + 1) : separatePosition;// 初始化路径隔断
if (file.isFile()) { // 是个正常文件,不是目录
compressNormalFile(file, zos, separatePosition);
} else if (file.listFiles().length == 0) { // 空文件夹
// compressEmptyDirectory(file, zos, separatePosition); 这个不行,被网上的某高手骗了
} else { // 含有内容的文件夹,循环处理
File[] files = file.listFiles();
if (files != null && files.length > 0) { // 空文件夹暂时不处理
for (File sf : files) {
compressSingeFile(sf, zos, separatePosition);
}
}
}
}
/**
* 压缩一个正常文件
*
* @param file
* @param zos
* @param separatePosition
* @throws IOException
*/
private static void compressNormalFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
String entryPath = file.getAbsolutePath().substring(separatePosition);
compressToPointedZipEnrty(file, zos, entryPath);
}
/**
* 压缩一个空文件夹
*
* @param file
* @param zos
* @param separatePosition
* @throws IOException
*/
private static void compressEmptyDirectory(File file, ZipOutputStream zos, Integer separatePosition) throws IOException { // 压缩空文件夹
String entryPath = file.getAbsolutePath().substring(separatePosition) + File.separator;
compressToPointedZipEnrty(file, zos, entryPath);
}
/**
* 压缩文件到一个指定名称的zipEntry
*
* @param file
* @param zos
* @param zipEntryName
* @throws IOException
*/
private static void compressToPointedZipEnrty(File file, ZipOutputStream zos, String zipEntryName) throws IOException { // 压缩空文件夹
FileInputStream fis = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(zipEntryName));
byte[] b = new byte[2000];
int tmp = 0;
if ((tmp = fis.read(b)) != -1) {
zos.write(b, 0, tmp);
}
fis.close(); // 哪里创建的流哪里关闭
}
/**
* java.util.zip.ZipOutputStream压缩多个文件
*
* @throws IOException
*/
static File compressFiles(File[] files, File zipFile) throws IOException {
if (files.length > 0) {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"));
for (File file : files) {
compressSingeFile(file, zos);
}
zos.flush();
zos.close();
}
return zipFile;
}
/**
* 解压文件到目录directoryPath下面
*
* @param file
* @param directoryPath
* @return
* @throws IOException
*/
static List<File> decompressFile(File zipFile, String directoryPath) throws IOException {
List<File> result = new ArrayList<File>();
File directory = new File(directoryPath);
if (!directory.exists()) { // 目录不存在
directory.mkdirs();
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry zipEntry = null;
while ((zipEntry = zis.getNextEntry()) != null) { // 便利zipFile中的zipEntry
File sFile = new File(directory.getAbsolutePath() + File.separator + zipEntry.getName());
System.out.println(zipEntry.getName());
// 这有个坑,如果是多层文件夹嵌套可能文件路径不存在,得校验
if (!sFile.getParentFile().exists()) {
sFile.getParentFile().mkdirs();
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
byte[] b = new byte[2000];
int tmp = 0;
while ((tmp = zis.read(b)) != -1) {
bos.write(b, 0, tmp);
}
bos.flush();
bos.close();
zis.closeEntry();
result.add(sFile);
}
zis.close();
return result;
}
}