jdk自身有zip相关的代码,不过直到1.6的版本没有提供设置字符集的接口,因此都会出现中文乱码,目前网上的方案大多需要引入ant包进行处理:
//创建org.apache.tools.zip.ZipOutputStream
ZipOutputStream zos = new ZipOutputStream(cos);
zos.setEncoding("gbk");
然而,1.7已经修复了这个问题
在jdk7中的java.util.zip.ZipOutputStream新增了这样一个构造方法:
/**
* Creates a new ZIP output stream.
*
* @param out the actual output stream
*
* @param charset the {@linkplain java.nio.charset.Charset charset}
* to be used to encode the entry names and comments
*
* @since 1.7
*/
public ZipOutputStream(OutputStream out, Charset charset) {
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
if (charset == null)
throw new NullPointerException("charset is null");
this.zc = ZipCoder.get(charset);
usesDefaultDeflater = true;
}
这就为我们设置字符集提供了接口
ZipOutputStream zos = new ZipOutputStream(cos, Charset.forName("gbk"));
这样一来两个方法基本来说可以算是等效了,后面的新增文件方法都相同的
给一个使用jdk自带ZipOutputStream的直接取得zip文件字节数组的方案
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Created with IntelliJ IDEA.
* User: yixian
* Date: 13-10-17
* Time: 下午2:52
* 将文件夹压缩并取回zip文件byte[]
*/
public class DefaultZipper implements IZipper {
private Set<String> filePathSet = new HashSet<String>();
private File targetFile;
private Logger logger = LoggerFactory.getLogger(getClass());
public DefaultZipper() {
String tempDirectory = FileUtils.getTempDirectoryPath();
if (!tempDirectory.endsWith(File.separator)) {
tempDirectory += File.separator;
}
targetFile = initRandomTarget(tempDirectory);
}
private synchronized File initRandomTarget(String tempDirectory) {
File target;
do {
String fileName = RandomStringUtils.random(20, true, true);
String targetFilePath = tempDirectory + fileName;
target = new File(targetFilePath);
} while (target.exists());
return target;
}
private boolean checkFilePath(String path) {
File file = new File(path);
return file.exists();
}
@Override
public boolean addFile(String filePath) {
if (checkFilePath(filePath)) {
filePathSet.add(filePath);
return true;
}
return false;
}
@Override
public String[] addFiles(String... paths) {
String[] notExistsFiles = new String[0];
for (String path : paths) {
if (!addFile(path)) {
ArrayUtils.add(notExistsFiles, path);
}
}
return notExistsFiles;
}
@Override
public byte[] doCompress() throws IOException {
FileOutputStream fos = new FileOutputStream(targetFile);
CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(cos, Charset.forName("gbk"));
String baseDir = "";
for (String filePath : filePathSet) {
compress(new File(filePath), zos, baseDir);
}
zos.close();
return loadTargetFileBytes();
}
private void compress(File file, ZipOutputStream zos, String basePath) {
if (file.isDirectory()) {
logger.debug("compressing dir:" + basePath + file.getName());
compressDirectory(file, zos, basePath);
} else {
logger.debug("compressing file:" + basePath + file.getName());
compressFile(file, zos, basePath);
}
}
private void compressDirectory(File dir, ZipOutputStream zos, String basePath) {
File[] childrenFiles = dir.listFiles();
for (File child : childrenFiles != null ? childrenFiles : new File[0]) {
compress(child, zos, basePath + dir.getName() + "/");
}
}
private void compressFile(File file, ZipOutputStream zos, String basePath) {
if (!file.exists()) {
return;
}
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
String entryName = basePath + file.getName();
ZipEntry entry = new ZipEntry(entryName);
zos.putNextEntry(entry);
byte[] buffer = FileUtils.readFileToByteArray(file);
zos.write(buffer);
zos.flush();
zos.closeEntry();
bis.close();
} catch (IOException ignored) {
}
}
private byte[] loadTargetFileBytes() {
try {
byte[] fileBytes = FileUtils.readFileToByteArray(targetFile);
boolean deleted = targetFile.delete();
logger.debug("file:" + targetFile.getAbsoluteFile() + " deleted:" + deleted);
return fileBytes;
} catch (IOException e) {
return new byte[0];
}
}
}
引入了两个commons包,给出Maven Dependency
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
测试:
import com.skytech.crius.city.util.DefaultZipper;
import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* User: yixian
* Date: 13-10-21
* Time: 上午10:30
*/
public class ZipTest {
private static final String SOURCE_FILE_PATH = "d:\\foo\\bar";
@Test
public void DefaultZipperTest() throws IOException {
IZipper zipper = new DefaultZipper();
zipper.addFile(SOURCE_FILE_PATH);
byte[] bytes = zipper.doCompress();
FileOutputStream fos = new FileOutputStream("d:\\test.zip");
fos.write(bytes);
fos.flush();
fos.close();
}
}
注意这个案例因为要把zip压缩文件整体读入内存所以如果压的文件体积太大就会......