前言
背景:公司项目有一个文件导出要求,并且要按照特定的目录结构组织
一、java.util.zip 是什么
java.util.zip 是 java 提供的对于压缩文件读写的工具包
二、使用步骤
1. 基本对象
class Node {
String name;
List<Node> nodes;
List<NodeFile> files;
public Node(String name) {
this.name = name;
}
}
class NodeFile {
File file;
String name;
public NodeFile(File file, String name) {
this.file = file;
this.name = name;
}
}
class FileProcess {
int total;
int completed;
}
2. 写数据
@Slf4j
public class ExportFile {
private FileProcess fileProcess;
public ExportFile() {
fileProcess = new FileProcess();
}
public void writeZipFile(String zipDir, String zipName, List<Node> nodes) {
ZipOutputStream zos = null;
FileOutputStream fos = null;
try {
File file = new File(zipDir);
if (!file.exists()) {
file.mkdirs();
}
File zipFile = new File(zipDir + File.separator + zipName);
zipFile.createNewFile();
fos = new FileOutputStream(zipFile);
zos = new ZipOutputStream(fos);
for (Node node : nodes) {
writeFile(zos, "", node);
}
} catch (Exception e) {
log.error("{}/{} 导出失败", zipDir, zipName, e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (Exception e) {
}
}
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
}
}
}
}
private void writeFile(ZipOutputStream zos, String dir, Node node) throws IOException {
String currPath = StringUtils.isEmpty(dir) ? node.name : (dir + File.separator + node.name);
writeFile2(zos, currPath, node.files);
if (node.nodes == null) {
return;
}
for (Node node1 : node.nodes) {
writeFile(zos, currPath, node1);
}
}
private void writeFile2(ZipOutputStream zos, String parentPath, List<NodeFile> files) throws IOException {
if (CollectionUtils.isEmpty(files)) {
return;
}
Map<String, Integer> fileIndex = new HashMap<>();
for (NodeFile file : files) {
Integer index;
String path;
if ((index = fileIndex.get(file.name)) == null) {
fileIndex.put(file.name, 0);
path = parentPath + File.separator + file.name;
} else {
index += 1;
fileIndex.put(file.name, index);
int index2 = file.name.lastIndexOf(".");
path = parentPath + File.separator + file.name.substring(0, index2) + "(" + index + ")" + file.name.substring(index2);
}
zos.putNextEntry(new ZipEntry(path));
copyFile(file.file, zos);
fileProcess.completed++;
}
}
private void copyFile(File file, ZipOutputStream zos) throws IOException {
FileInputStream is = null;
try {
is = new FileInputStream(file);
byte[] bytes = new byte[1024];
int length;
while ((length = is.read(bytes)) > 0) {
zos.write(bytes, 0, length);
}
} catch (IOException e) {
log.error("写文件失败 {}", file.getAbsolutePath(), e);
throw e;
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
}
}
try {
zos.closeEntry();
} catch (Exception e) {
}
}
}
public FileProcess getFileProcess() {
return fileProcess;
}
public void setFileProcess(FileProcess fileProcess) {
this.fileProcess = fileProcess;
}
public static void main(String[] args) {
ExportFile file = new ExportFile();
List<Node> list = new ArrayList<>();
Node n = new Node("test");
NodeFile f = new NodeFile(new File("/path/file.png"), "filename.png");
n.files = Arrays.asList(f);
list.add(n);
file.writeZipFile("/path", "text.zip", list);
}
}
总结
通过ZipOutputStream,每一个文件对应一个 ZipEntry
|