如何在 Java 中创建一个 zip 文件

我有一个动态文本文件,它根据用户的查询从数据库中挑选内容。我必须将这些内容写入一个文本文件,并将其压缩到 servlet 中的一个文件夹中。我该怎么做?

299113 次浏览

看看这个例子:

StringBuilder sb = new StringBuilder();
sb.append("Test String");


File f = new File("d:\\test.zip");
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f));
ZipEntry e = new ZipEntry("mytext.txt");
out.putNextEntry(e);


byte[] data = sb.toString().getBytes();
out.write(data, 0, data.length);
out.closeEntry();


out.close();

这将在 D:的根目录中创建一个名为 test.zip的 zip,它将包含一个名为 mytext.txt的文件。当然,您可以添加更多的 zip 条目,也可以像下面这样指定一个子目录:

ZipEntry e = new ZipEntry("folderName/mytext.txt");

您可以找到更多关于使用 Java给你进行压缩的信息。

要编写 ZIP 文件,可以使用 ZipOutputStream。对于要放入 ZIP 文件中的每个条目,都要创建一个 ZipEntry 对象。将文件名传递给 ZipEntry 构造函数; 它设置其他参数,如文件日期和解压方法。如果愿意,可以重写这些设置。然后,调用 ZipOutputStream 的 putNextEntry 方法开始编写新文件。将文件数据发送到 ZIP 流。完成后,调用 closeEntry。对要存储的所有文件重复执行此操作。下面是一个代码框架:

FileOutputStream fout = new FileOutputStream("test.zip");
ZipOutputStream zout = new ZipOutputStream(fout);
for all files
{
ZipEntry ze = new ZipEntry(filename);
zout.putNextEntry(ze);
send data to zout;
zout.closeEntry();
}
zout.close();
public static void main(String args[])
{
omtZip("res/", "omt.zip");
}
public static void omtZip(String path,String outputFile)
{
final int BUFFER = 2048;
boolean isEntry = false;
ArrayList<String> directoryList = new ArrayList<String>();
File f = new File(path);
if(f.exists())
{
try {
FileOutputStream fos = new FileOutputStream(outputFile);
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
byte data[] = new byte[BUFFER];


if(f.isDirectory())
{
//This is Directory
do{
String directoryName = "";
if(directoryList.size() > 0)
{
directoryName = directoryList.get(0);
System.out.println("Directory Name At 0 :"+directoryName);
}
String fullPath = path+directoryName;
File fileList = null;
if(directoryList.size() == 0)
{
//Main path (Root Directory)
fileList = f;
}else
{
//Child Directory
fileList = new File(fullPath);
}
String[] filesName = fileList.list();


int totalFiles = filesName.length;
for(int i = 0 ; i < totalFiles ; i++)
{
String name = filesName[i];
File filesOrDir = new File(fullPath+name);
if(filesOrDir.isDirectory())
{
System.out.println("New Directory Entry :"+directoryName+name+"/");
ZipEntry entry = new ZipEntry(directoryName+name+"/");
zos.putNextEntry(entry);
isEntry = true;
directoryList.add(directoryName+name+"/");
}else
{
System.out.println("New File Entry :"+directoryName+name);
ZipEntry entry = new ZipEntry(directoryName+name);
zos.putNextEntry(entry);
isEntry = true;
FileInputStream fileInputStream = new FileInputStream(filesOrDir);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, BUFFER);
int size = -1;
while(  (size = bufferedInputStream.read(data, 0, BUFFER)) != -1  )
{
zos.write(data, 0, size);
}
bufferedInputStream.close();
}
}
if(directoryList.size() > 0 && directoryName.trim().length() > 0)
{
System.out.println("Directory removed :"+directoryName);
directoryList.remove(0);
}


}while(directoryList.size() > 0);
}else
{
//This is File
//Zip this file
System.out.println("Zip this file :"+f.getPath());
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis,BUFFER);
ZipEntry entry = new ZipEntry(f.getName());
zos.putNextEntry(entry);
isEntry = true;
int size = -1 ;
while(( size = bis.read(data,0,BUFFER)) != -1)
{
zos.write(data, 0, size);
}
}


//CHECK IS THERE ANY ENTRY IN ZIP ? ----START
if(isEntry)
{
zos.close();
}else
{
zos = null;
System.out.println("No Entry Found in Zip");
}
//CHECK IS THERE ANY ENTRY IN ZIP ? ----START
}catch(Exception e)
{
e.printStackTrace();
}
}else
{
System.out.println("File or Directory not found");
}
}


}

Java7内置了 ZipFileSystem,可用于从 zip 文件创建、写入和读取文件。

ZipFileSystem 提供程序

Map<String, String> env = new HashMap<>();
// Create the zip file if it doesn't exist
env.put("create", "true");


URI uri = URI.create("jar:file:/codeSamples/zipfs/zipfstest.zip");


try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path externalTxtFile = Paths.get("/codeSamples/zipfs/SomeTextFile.txt");
Path pathInZipfile = zipfs.getPath("/SomeTextFile.txt");
// Copy a file into the zip file
Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
}

如果你不想用软件解压缩,最好使用这个代码。其他代码与 pdf 文件发送手动解压缩错误

byte[] buffer = new byte[1024];


try {
   

FileOutputStream fos = new FileOutputStream("123.zip");
ZipOutputStream zos = new ZipOutputStream(fos);
ZipEntry ze= new ZipEntry("file.pdf");
zos.putNextEntry(ze);


FileInputStream in = new FileInputStream("file.pdf");
int len;


while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}


in.close();
zos.closeEntry();
zos.close();


} catch(IOException ex) {
ex.printStackTrace();
}

Spring 启动控制器,将文件压缩到一个目录中,并且可以下载。

@RequestMapping(value = "/files.zip")
@ResponseBody
byte[] filesZip() throws IOException {
File dir = new File("./");
File[] filesArray = dir.listFiles();
if (filesArray == null || filesArray.length == 0)
System.out.println(dir.getAbsolutePath() + " have no file!");
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ZipOutputStream zipOut= new ZipOutputStream(bo);
for(File xlsFile:filesArray){
if(!xlsFile.isFile())continue;
ZipEntry zipEntry = new ZipEntry(xlsFile.getName());
zipOut.putNextEntry(zipEntry);
zipOut.write(IOUtils.toByteArray(new FileInputStream(xlsFile)));
zipOut.closeEntry();
}
zipOut.close();
return bo.toByteArray();
}

由于我花了一段时间才弄明白,我认为使用 Java7 + ZipFileSystem 发布我的解决方案会很有帮助

 openZip(runFile);


addToZip(filepath); //loop construct;


zipfs.close();


private void openZip(File runFile) throws IOException {
Map<String, String> env = new HashMap<>();
env.put("create", "true");
env.put("encoding", "UTF-8");
Files.deleteIfExists(runFile.toPath());
zipfs = FileSystems.newFileSystem(URI.create("jar:" + runFile.toURI().toString()), env);
}


private void addToZip(String filename) throws IOException {
Path externalTxtFile = Paths.get(filename).toAbsolutePath();
Path pathInZipfile = zipfs.getPath(filename.substring(filename.lastIndexOf("results"))); //all files to be stored have a common base folder, results/ in my case
if (Files.isDirectory(externalTxtFile)) {
Files.createDirectories(pathInZipfile);
try (DirectoryStream<Path> ds = Files.newDirectoryStream(externalTxtFile)) {
for (Path child : ds) {
addToZip(child.normalize().toString()); //recursive call
}
}
} else {
// copy file to zip file
Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
}
}

下面是一个压缩 完整目录(包括子文件和子目录)的示例代码,它使用了 JavaNIO 的遍历文件树特性。

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


public class ZipCompress {
public static void compress(String dirPath) {
final Path sourceDir = Paths.get(dirPath);
String zipFileName = dirPath.concat(".zip");
try {
final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {
try {
Path targetFile = sourceDir.relativize(file);
outputStream.putNextEntry(new ZipEntry(targetFile.toString()));
byte[] bytes = Files.readAllBytes(file);
outputStream.write(bytes, 0, bytes.length);
outputStream.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
});
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

要使用这个,只要打电话

ZipCompress.compress("target/directoryToCompress");

你会得到一个 zip 文件 directoryToCompress.zip

下面是如何从源文件创建 zip 文件:

String srcFilename = "C:/myfile.txt";
String zipFile = "C:/myfile.zip";


try {
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
File srcFile = new File(srcFilename);
FileInputStream fis = new FileInputStream(srcFile);
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
zos.close();
}
catch (IOException ioe) {
System.out.println("Error creating zip file" + ioe);
}

一列纵队:

String filePath = "/absolute/path/file1.txt";
String zipPath = "/absolute/path/output.zip";


try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
File fileToZip = new File(filePath);
zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
Files.copy(fileToZip.toPath(), zipOut);
}

多个文件:

List<String> filePaths = Arrays.asList("/absolute/path/file1.txt", "/absolute/path/file2.txt");
String zipPath = "/absolute/path/output.zip";


try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
for (String filePath : filePaths) {
File fileToZip = new File(filePath);
zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
Files.copy(fileToZip.toPath(), zipOut);
}
}
public static void zipFromTxt(String zipFilePath, String txtFilePath) {
Assert.notNull(zipFilePath, "Zip file path is required");
Assert.notNull(txtFilePath, "Txt file path is required");
zipFromTxt(new File(zipFilePath), new File(txtFilePath));
}


public static void zipFromTxt(File zipFile, File txtFile) {
ZipOutputStream out = null;
FileInputStream in = null;
try {
Assert.notNull(zipFile, "Zip file is required");
Assert.notNull(txtFile, "Txt file is required");
out = new ZipOutputStream(new FileOutputStream(zipFile));
in = new FileInputStream(txtFile);
out.putNextEntry(new ZipEntry(txtFile.getName()));
int len;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
out.flush();
}
} catch (Exception e) {
log.info("Zip from txt occur error,Detail message:{}", e.toString());
} finally {
try {
if (in != null) in.close();
if (out != null) {
out.closeEntry();
out.close();
}
} catch (Exception e) {
log.info("Zip from txt close error,Detail message:{}", e.toString());
}
}
}

给定 exportPathqueryResults作为 String 变量,下面的代码块在 exportPath下创建一个 results.zip文件,并将 queryResults的内容写入 zip 中的一个 results.txt文件。

URI uri = URI.create("jar:file:" + exportPath + "/results.zip");
Map<String, String> env = Collections.singletonMap("create", "true");


try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path filePath = zipfs.getPath("/results.txt");
byte[] fileContent = queryResults.getBytes();


Files.write(filePath, fileContent, StandardOpenOption.CREATE);
}

您主要需要创建两个函数。第一个是 writeToZipFile () ,第二个是 createZipfileForOutput... 。然后调用 createZipfileForOutput (’文件名为。’)’..。

 public static void writeToZipFile(String path, ZipOutputStream zipStream)
throws FileNotFoundException, IOException {


System.out.println("Writing file : '" + path + "' to zip file");


File aFile = new File(path);
FileInputStream fis = new FileInputStream(aFile);
ZipEntry zipEntry = new ZipEntry(path);
zipStream.putNextEntry(zipEntry);


byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipStream.write(bytes, 0, length);
}


zipStream.closeEntry();
fis.close();
}


public static void createZipfileForOutPut(String filename) {
String home = System.getProperty("user.home");
// File directory = new File(home + "/Documents/" + "AutomationReport");
File directory = new File("AutomationReport");
if (!directory.exists()) {
directory.mkdir();
}
try {
FileOutputStream fos = new FileOutputStream("Path to your destination" + filename + ".zip");
ZipOutputStream zos = new ZipOutputStream(fos);


writeToZipFile("Path to file which you want to compress / zip", zos);




zos.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

使用 Jeka https://jeka.dev JkPathTree 非常简单。

Path wholeDirToZip = Paths.get("dir/to/zip");
Path zipFile = Paths.get("file.zip");
JkPathTree.of(wholeDirToZip).zipTo(zipFile);

https://github.com/srikanth-lingala/zip4j处使用 zip4j还有另一个选项

创建包含单个文件的 zip 文件/向现有 zip 添加单个文件

new ZipFile("filename.zip").addFile("filename.ext"); 或者

new ZipFile("filename.zip").addFile(new File("filename.ext"));

创建包含多个文件的 zip 文件/向现有 zip 添加多个文件

new ZipFile("filename.zip").addFiles(Arrays.asList(new File("first_file"), new File("second_file")));

通过向压缩文件添加文件夹/向现有压缩文件添加文件夹来创建压缩文件

new ZipFile("filename.zip").addFolder(new File("/user/myuser/folder_to_add"));

从 stream 创建 zip 文件/将 stream 添加到现有 zip new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());

我知道这个问题已经得到了回答,但是如果您有一个字符串列表,并且希望为存档中的每个字符串创建一个单独的文件,那么可以使用下面的代码片段。

public void zipFileTest() throws IOException {


Map<String, String> map = Map.ofEntries(
new AbstractMap.SimpleEntry<String, String>("File1.txt", "File1 Content"),
new AbstractMap.SimpleEntry<String, String>("File2.txt", "File2 Content"),
new AbstractMap.SimpleEntry<String, String>("File3.txt", "File3 Content")
);


createZipFileFromStringContents(map, "archive.zip");


}


public void createZipFileFromStringContents(Map<String, String> map, String zipfilePath) throws IOException {


FileOutputStream fout = new FileOutputStream(zipfilePath);
ZipOutputStream zout = new ZipOutputStream(fout);


for (Map.Entry<String, String> entry : map.entrySet()) {
String fileName = entry.getKey();
ZipEntry zipFile = new ZipEntry(fileName);
zout.putNextEntry(zipFile);
String fileContent = entry.getValue();
zout.write(fileContent.getBytes(), 0, fileContent.getBytes().length);
zout.closeEntry();
}


zout.close();
}

它将创建一个 zip 文件,其结构如下图所示:

zip file structure

以下是我的工作解决方案:

public static byte[] createZipFile(Map<String, FileData> files) throws IOException {
try(ByteArrayOutputStream tZipFile = new ByteArrayOutputStream()) {
try (ZipOutputStream tZipFileOut = new ZipOutputStream(tZipFile)) {
for (Map.Entry<String, FileData> file : files.entrySet()) {
ZipEntry zipEntry = new ZipEntry(file.getValue().getFileName());
tZipFileOut.putNextEntry(zipEntry);
tZipFileOut.write(file.getValue().getBytes());
}
}


return tZipFile.toByteArray();
}
}


public class FileData {
private String fileName;
private byte[] bytes;


public String getFileName() {
return this.fileName;
}


public byte[] getBytes() {
return this.bytes;
}
}

这将创建包含一个或多个压缩文件的 ZIP 文件的 byte []。我在控制器方法中使用了这个方法,并将 ZIP 文件的字节[]写入到响应中,以便从服务器下载 ZIP 文件。