Java中的Zip文件操作
目录
Java中的Zip文件操作
0. 简介
- 简单的生成和读取 zip 文件
package com.willhonor.test;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.junit.Test;
/**
* 有两处可能需要指定编码
* <br>1. zipEntry 的名称和 comment 的编码可以单独指定
* <br>2. zipEntry 的内容编码,该部分只需编码与解码方案一致即可,可以使用任意编码,
* <br>即 如果写入数据时,使用 utf-8 编码,则读取数据时也使用 utf-8 解码即可。
* @author jokee
*
*/
public class Test_1 {
/** 1. 生成 zip 文件
* <br> a. 先指定 zipEntry 的名称,然后为其写入数据,这里的数据部分以字节数组的形式提供,
* <br>所以可以采用任意编码,当然在提取该 zipEntry 的数据内容时,也必须采用一致的解码方案。
*/
@Test
public void test_generateZipFile() throws Exception {
String zipFile = "E:\\temp\\temp\\docs.zip";
// create new zip file
File file = new File(zipFile);
if (file.exists()) {
file.delete();
}
file.createNewFile();
// zipEntry 名称和 comment 使用 utf-8 编码
ZipOutputStream zipOutputStream
= new ZipOutputStream(new FileOutputStream(file), UTF_8);
// zipOutputStream.setComment("这是文档文件,压缩包");
zipOutputStream.setComment("this is zip file, just for test.");
// 1 first file,zipEntry 内容数据使用 utf-8 编码
byte[] f1 = "hello this world, I'm here now, so happy!".getBytes(UTF_8);
addEntry(zipOutputStream, "hello.txt", f1);
// 2 second file
byte[] f2 = "<p>这是我最喜欢的 blog 网站了</p>".getBytes(UTF_8);
addEntry(zipOutputStream, "我的书签收藏.html", f2);
// 4 empty directory
addEntry(zipOutputStream, "others\\", null);
addEntry(zipOutputStream, "其它\\", null);
addEntry(zipOutputStream, "com\\", null);
addEntry(zipOutputStream, "com\\will\\", null);
addEntry(zipOutputStream, "com\\will\\honor\\", null);
// 3 third file
byte[] f3 = "/** this is java source */".getBytes(UTF_8);
addEntry(zipOutputStream, "com/will/honor/test.java", f3);
// close
zipOutputStream.close();
}
private void addEntry(ZipOutputStream os, String entityName, byte[] bytes) {
try {
ZipEntry entry = new ZipEntry(entityName);
os.putNextEntry(entry);
if (bytes != null && bytes.length > 0) {
os.write(bytes);
}
os.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
/** 读取/打印压缩文件内容,这里使用文本文件作为实验。通常 zip 文件中会包含例如 pdf/png 等格式的文件,不适合打印 */
@Test
public void test_useZipFileClass() throws Exception {
String fileName = "E:\\temp\\temp\\docs.zip";
// String fileName = "E:\\temp\\temp\\usediffcharset.zip";
// zipEntry 名称和 commend 使用 utf-8 解码
ZipFile zipFile = new ZipFile(new File(fileName), UTF_8);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while(entries.hasMoreElements()) {
ZipEntry en = entries.nextElement();
System.out.println(String.format("[%s]", new Object[] {en.getName()}));
if (!en.isDirectory()) {
InputStream is = zipFile.getInputStream(en);
byte[] bytes = getAllBytes(is);
// zipEntry 内容使用 utf-8 解码
System.out.println(new String(bytes, UTF_8) + "\n---------------");
}
}
zipFile.close();
}
public byte[] getAllBytes(InputStream is) {
if (is != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int bufSize = 1024;
byte[] buf = new byte[bufSize];
int res = 0;
try {
while((res = is.read(buf)) > 0) {
out.write(buf, 0, res);
}
} catch (IOException e) {
e.printStackTrace();
}
return out.toByteArray();
}
return null;
}
/**
* zipEntry 的名称使用 UTF-8 编码,而其数据内容使用 gbk 编码
*/
@Test
public void test_useDifferentCharset() throws Exception {
String fileName = "E:\\temp\\temp\\usediffcharset.zip";
File file = new File(fileName);
if (file.exists()) {
file.delete();
}
file.createNewFile();
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(file), UTF_8);
// add 1
// zipEntry 名称使用 utf-8 编码
zipOutputStream.putNextEntry(new ZipEntry("Java编程实战.txt"));
// zipEntry 内容使用 gbk 编码
zipOutputStream.write("这是Java编程实战,这是注释".getBytes(Charset.forName("gbk")));
//
zipOutputStream.close();
}
}
- 压缩指定的目录或文件(zipEntry 名称和 comment 使用 utf-8 编码,zipEntry 内容保持不变,即不对 zipEntry 内容重新解码和编码)
package com.willhonor.test;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.junit.Test;
/**
* 压缩指定的目录 或 文件
* @author jokee
*
*/
public class Test_2 {
public static final String FILE_SYSTEM_SEPARATOR = FileSystems.getDefault().getSeparator();
public static void main(String[] args) {
String path = "E:\\360Downloads\\Software";
String zipFileName = "E:\\360Downloads\\";
doZip(path, zipFileName);
}
/**
*
* @param filePath 需要被压缩的目录或文件
* @param zipFileName 生成的压缩文件,如果为 null ,则生成的压缩文件处于 filePath 路径同级
*/
public static void doZip(String filePath, String zipFileName) {
if (filePath != null) {
Path path = Paths.get(filePath, new String[] {});
if (Files.notExists(path, new LinkOption[] {LinkOption.NOFOLLOW_LINKS})) {
System.out.println("指定路径不存在,path:" + path.toString());
System.out.println("程序退出");
System.exit(1);
}
Path parentPath = path.getParent();
final int parentPathLen = parentPath.toString().length();
zipFileName = getZipFileName(path, zipFileName);
File zipFile = createZipFileIfNotExist(zipFileName);
try {
final ZipOutputStream os = new ZipOutputStream(new FileOutputStream(zipFile), UTF_8);
if (Files.isDirectory(path, new LinkOption[] {LinkOption.NOFOLLOW_LINKS})) {
// is directory
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
os.putNextEntry(new ZipEntry(dir.toString()
.substring(parentPathLen + FILE_SYSTEM_SEPARATOR.length())
+ FILE_SYSTEM_SEPARATOR));
os.closeEntry();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
os.putNextEntry(new ZipEntry(path.toString()
.substring(parentPathLen + FILE_SYSTEM_SEPARATOR.length())));
os.write(Files.readAllBytes(path));
os.closeEntry();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}else {
// is a file
os.putNextEntry(new ZipEntry(path.toString()
.substring(parentPathLen + FILE_SYSTEM_SEPARATOR.length())));
os.write(Files.readAllBytes(path));
os.closeEntry();
}
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String getZipFileName(Path path, String zipFileName) {
String fileName = path.getFileName().toString();
if (zipFileName == null) {
Path parenPath = path.getParent();
zipFileName = parenPath.toString() + FILE_SYSTEM_SEPARATOR + fileName + ".zip";
} else {
if (zipFileName.endsWith(FILE_SYSTEM_SEPARATOR)) {
// zipFileName 为目录
zipFileName += fileName;
}
if (!zipFileName.endsWith(".zip")) {
zipFileName += ".zip";
}
}
return zipFileName;
}
private static File createZipFileIfNotExist(String zipFileName) {
File file = new File(zipFileName);
if (!file.exists()) {
File parentFile = file.getParentFile();
if (parentFile != null && !parentFile.exists()) {
parentFile.mkdirs();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
}