如何在 Java 中创建一个 zip 文件
Posted
技术标签:
【中文标题】如何在 Java 中创建一个 zip 文件【英文标题】:How to create a zip file in Java 【发布时间】:2010-11-08 16:08:47 【问题描述】:我有一个动态文本文件,它根据用户的查询从数据库中挑选内容。我必须将此内容写入文本文件并将其压缩到 servlet 的文件夹中。我该怎么做?
【问题讨论】:
【参考方案1】:我知道这个问题已经得到解答,但如果你有一个字符串列表,并且你想为存档中的每个字符串创建一个单独的文件,你可以使用下面的 sn-p。
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 文件:
【讨论】:
【参考方案2】:在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")));
通过向其添加文件夹/向现有 zip 添加文件夹来创建 zip 文件
new ZipFile("filename.zip").addFolder(new File("/user/myuser/folder_to_add"));
从流创建 zip 文件/将流添加到现有 zip
new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());
【讨论】:
【参考方案3】:使用Jeka https://jeka.devJkPathTree,很简单。
Path wholeDirToZip = Paths.get("dir/to/zip");
Path zipFile = Paths.get("file.zip");
JkPathTree.of(wholeDirToZip).zipTo(zipFile);
【讨论】:
【参考方案4】:您主要需要创建两个函数。首先是 writeToZipFile(),其次是 createZipfileForOutPut .... 然后调用 createZipfileForOutPut('file name of .zip')` ...
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();
【讨论】:
【参考方案5】:看这个例子:
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
的压缩包,其中将包含一个名为mytext.txt
的文件。当然,你可以添加更多的 zip 条目,也可以像这样指定一个子目录:
ZipEntry e = new ZipEntry("folderName/mytext.txt");
您可以找到有关使用 Java here 进行压缩的更多信息。
【讨论】:
为什么这两行:byte[] data = sb.toString().getBytes(); out.write(data, 0, data.length);
包含在此代码示例中?他们的目的是什么?
@kdzia,第一行将 StringBuilder 值转换为字节数组,第二行获取该字节数组并将其写入“test.zip”文件中的 ZipEntry。这些行是必要的,因为 Zip 文件使用字节数组,而不是字符串。
但是......在上面的例子中,除了“测试字符串”之外,StringBuilder 中还有什么其他内容吗?我对此也有些困惑。如果您将 sb.toString().getBytes()
写入 ZIP 文件,我希望您希望它包含您正在压缩的文件的字节?还是我错过了什么?
@RobA 你没有错过任何东西。 StringBuilder 确实是为了包含 OP 从他的数据库中获得的文本。 OP 只需将“测试字符串”(包括引号)替换为 getTextFromDatabase()
谢谢,@Blueriver【参考方案6】:
Java 7 内置了 ZipFileSystem,可用于从 zip 文件创建、写入和读取文件。
Java Doc: ZipFileSystem Provider
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);
【讨论】:
如果扩展名不是.zip
,有没有办法让它工作?我需要编写一个.foo
文件,其格式与 zip 文件完全相同,但扩展名不同。我知道我可以创建一个.zip
文件并重命名它,但是使用正确的名称创建它会更简单。
@TroyDaniels 上面的示例也适用于不同的扩展名,因为它使用 jar:file:
前缀来创建 URI。
这里可能出现的唯一问题是,如果您有目录,它将无法工作。因此,例如,如果 pathInZipfile
变量中有“/dir/SomeTextFile.txt”,则需要在 .zip 存档中创建“dir”。为此,只需在调用 Files.copy
方法之前添加下一行:Files.createDirectories(pathInZipfile.getParent())
。
如何设置压缩级别?【参考方案7】:
将exportPath
和queryResults
作为字符串变量,以下代码块在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);
【讨论】:
【参考方案8】:这是一个压缩整个目录(包括子文件和子目录)的示例代码,它使用了Java NIO的walk file tree特性。
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文件。【参考方案9】: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());
【讨论】:
【参考方案10】:单个文件:
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);
【讨论】:
【参考方案11】:这是从源文件创建 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);
【讨论】:
【参考方案12】:由于我花了一段时间才弄清楚,我认为使用 Java 7+ 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);
【讨论】:
【参考方案13】:Spring boot 控制器,将文件压缩到一个目录下,即可下载。
@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();
【讨论】:
【参考方案14】:如果您想在没有软件的情况下解压缩,最好使用此代码。其他带有 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();
【讨论】:
【参考方案15】: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");
【讨论】:
【参考方案16】:要编写 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();
【讨论】:
以上是关于如何在 Java 中创建一个 zip 文件的主要内容,如果未能解决你的问题,请参考以下文章
Java:如何使用 java.nio.file.FileSystem 在 zip 中创建目录
如何在 plsql (Oracle) 中创建 zip 文件夹