使用Java提供的核心库,
java.util.zip
public class ZipMultipleFiles {public static void main(String[] args) throws IOException {// 文件所在的路径List<String> srcFiles &#61; Arrays.asList("src/main/resources/test1.txt", "src/main/resources/test2.txt");// 构造压缩文件对象FileOutputStream fos &#61; new FileOutputStream("src/main/resources/multiCompressed.zip");ZipOutputStream zipOut &#61; new ZipOutputStream(fos);// 向压缩包对象中添加多个文件for (String srcFile : srcFiles) {File fileToZip &#61; new File(srcFile);ZipEntry zipEntry &#61; new ZipEntry(fileToZip.getName());zipOut.putNextEntry(zipEntry);FileInputStream fis &#61; new FileInputStream(fileToZip);byte[] bytes &#61; new byte[1024];int length;while((length &#61; fis.read(bytes)) >&#61; 0) {// 将文件信息写入压缩文件中zipOut.write(bytes, 0, length);}fis.close();}zipOut.close();fos.close();}
}
ZipEntry
保存到压缩包中&#xff0c;从而保持压缩的目录结构。public class ZipDirectory {public static void main(String[] args) throws IOException, FileNotFoundException {// 需要被压缩的文件夹String sourceFile &#61; "src/main/resources/zipTest";// 文件夹压缩之后的文件夹对象FileOutputStream fos &#61; new FileOutputStream("src/main/resources/dirCompressed.zip");ZipOutputStream zipOut &#61; new ZipOutputStream(fos);// 递归压缩文件夹File fileToZip &#61; new File(sourceFile);zipFile(fileToZip, fileToZip.getName(), zipOut);// 关闭输出流zipOut.close();fos.close();}/*** 将fileToZip文件夹及其子目录文件递归压缩到zip文件中* &#64;param fileToZip 递归当前处理对象&#xff0c;可能是文件夹&#xff0c;也可能是文件* &#64;param fileName fileToZip文件或文件夹名称* &#64;param zipOut 压缩文件输出流* &#64;throws IOException*/private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {// 不压缩隐藏文件夹if (fileToZip.isHidden()) {return;}// 判断压缩对象如果是一个文件夹if (fileToZip.isDirectory()) {if (fileName.endsWith("/")) {// 如果文件夹是以“/”结尾&#xff0c;将文件夹作为压缩箱放入zipOut压缩输出流zipOut.putNextEntry(new ZipEntry(fileName));zipOut.closeEntry();} else {// 如果文件夹不是以“/”结尾&#xff0c;将文件夹结尾加上“/”之后作为压缩箱放入zipOut压缩输出流zipOut.putNextEntry(new ZipEntry(fileName &#43; "/"));zipOut.closeEntry();}// 遍历文件夹子目录&#xff0c;进行递归的zipFileFile[] children &#61; fileToZip.listFiles();for (File childFile : children) {zipFile(childFile, fileName &#43; "/" &#43; childFile.getName(), zipOut);}//如果当前递归对象是文件夹&#xff0c;加入ZipEntry之后就返回return;}// 如果当前的fileToZip不是一个文件夹&#xff0c;是一个文件&#xff0c;将其以字节码形式压缩到压缩包里面FileInputStream fis &#61; new FileInputStream(fileToZip);ZipEntry zipEntry &#61; new ZipEntry(fileName);zipOut.putNextEntry(zipEntry);byte[] bytes &#61; new byte[1024];int length;while ((length &#61; fis.read(bytes)) >&#61; 0) {zipOut.write(bytes, 0, length);}// 关闭流fis.close();}}
二.zip解压缩
public class UnzipFile {public static void main(String[] args) throws IOException {// 需要被解压的压缩文件String fileZip &#61; "src/main/resources/unzipTest/compressed.zip";// 解压的目标目录File destDir &#61; new File("src/main/resources/unzipTest");byte[] buffer &#61; new byte[1024];ZipInputStream zis &#61; new ZipInputStream(new FileInputStream(fileZip));// 获取压缩包中的entry&#xff0c;并将其解压ZipEntry zipEntry &#61; zis.getNextEntry();while (zipEntry !&#61; null) {File newFile &#61; newFile(destDir, zipEntry);FileOutputStream fos &#61; new FileOutputStream(newFile);int len;while ((len &#61; zis.read(buffer)) > 0) {fos.write(buffer, 0, len);}fos.close();//解压完成一个entry&#xff0c;再解压下一个zipEntry &#61; zis.getNextEntry();}zis.closeEntry();zis.close();}// 在解压目标文件夹&#xff0c;新建一个文件public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {File destFile &#61; new File(destinationDir, zipEntry.getName());String destDirPath &#61; destinationDir.getCanonicalPath();String destFilePath &#61; destFile.getCanonicalPath();if (!destFilePath.startsWith(destDirPath &#43; File.separator)) {throw new IOException("该解压项在目标文件夹之外: " &#43; zipEntry.getName());}return destFile;}
}
三.压缩为tar.gz
java中没有一种官方的API可以去创建tar.gz
文件。所以我们需要使用到第三方库Apache Commons Compress去创建.tar.gz
文件。
.tar
.gz
tar.gz
或.tgz
通常是指将文件打包到一个tar文件中&#xff0c;并将它使用Gzip进行压缩。maven坐标
<dependency><groupId>org.apache.commonsgroupId><artifactId>commons-compressartifactId><version>1.20version>
dependency>
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.junit.jupiter.api.Test;import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;public class TarGzTest {&#64;Testvoid testFilesTarGzip() throws IOException {// 输入文件&#xff0c;被压缩文件Path path1 &#61; Paths.get("/home/test/file-a.xml");Path path2 &#61; Paths.get("/home/test/file-b.txt");List<Path> paths &#61; Arrays.asList(path1, path2);//输出文件压缩结果Path output &#61; Paths.get("/home/test/output.tar.gz");// OutputStream输出流、BufferedOutputStream缓冲输出流// GzipCompressorOutputStream是gzip压缩输出流// TarArchiveOutputStream打tar包输出流&#xff08;包含gzip压缩输出流&#xff09;try (OutputStream fOut &#61; Files.newOutputStream(output);BufferedOutputStream buffOut &#61; new BufferedOutputStream(fOut);GzipCompressorOutputStream gzOut &#61; new GzipCompressorOutputStream(buffOut);TarArchiveOutputStream tOut &#61; new TarArchiveOutputStream(gzOut)) {// 遍历文件listfor (Path path : paths) {// 该文件不是目录或者符号链接if (!Files.isRegularFile(path)) {throw new IOException("Support only file!");}// 将该文件放入tar包&#xff0c;并执行gzip压缩TarArchiveEntry tarEntry &#61; new TarArchiveEntry(path.toFile(),path.getFileName().toString());tOut.putArchiveEntry(tarEntry);Files.copy(path, tOut);tOut.closeArchiveEntry();}// for循环完成之后&#xff0c;finish-tar包输出流tOut.finish();}}
}
&#64;Test
void testDirTarGzip() throws IOException {// 被压缩打包的文件夹Path source &#61; Paths.get("/home/test");// 如果不是文件夹抛出异常if (!Files.isDirectory(source)) {throw new IOException("请指定一个文件夹");}// 压缩之后的输出文件名称String tarFileName &#61; "/home/" &#43; source.getFileName().toString() &#43; ".tar.gz";// OutputStream输出流、BufferedOutputStream缓冲输出流// GzipCompressorOutputStream是gzip压缩输出流// TarArchiveOutputStream打tar包输出流&#xff08;包含gzip压缩输出流&#xff09;try (OutputStream fOut &#61; Files.newOutputStream(Paths.get(tarFileName));BufferedOutputStream buffOut &#61; new BufferedOutputStream(fOut);GzipCompressorOutputStream gzOut &#61; new GzipCompressorOutputStream(buffOut);TarArchiveOutputStream tOut &#61; new TarArchiveOutputStream(gzOut)) {// 遍历文件目录树Files.walkFileTree(source, new SimpleFileVisitor<Path>() {//当成功访问到一个文件&#64;Overridepublic FileVisitResult visitFile(Path file,BasicFileAttributes attributes) throws IOException {// 判断当前遍历文件是不是符号链接(快捷方式)&#xff0c;不做打包压缩处理if (attributes.isSymbolicLink()) {return FileVisitResult.CONTINUE;}// 获取当前遍历文件名称Path targetFile &#61; source.relativize(file);// 将该文件打包压缩TarArchiveEntry tarEntry &#61; new TarArchiveEntry(file.toFile(), targetFile.toString());tOut.putArchiveEntry(tarEntry);Files.copy(file, tOut);tOut.closeArchiveEntry();// 继续下一个遍历文件处理return FileVisitResult.CONTINUE;}// 当前遍历文件访问失败&#64;Overridepublic FileVisitResult visitFileFailed(Path file, IOException exc) {System.err.printf("无法对该文件压缩打包为tar.gz : %s%n%s%n", file, exc);return FileVisitResult.CONTINUE;}});// for循环完成之后&#xff0c;finish-tar包输出流tOut.finish();}
}
四.tar.gz解压缩
&#64;Test
public void testDeCompressTarGzip() throws IOException {// 解压文件Path source &#61; Paths.get("/home/test/output.tar.gz");// 解压到哪Path target &#61; Paths.get("/home/test2");if (Files.notExists(source)) {throw new IOException("您要解压的文件不存在");}// InputStream输入流&#xff0c;以下四个流将tar.gz读取到内存并操作// BufferedInputStream缓冲输入流// GzipCompressorInputStream解压输入流// TarArchiveInputStream解tar包输入流try (InputStream fi &#61; Files.newInputStream(source);BufferedInputStream bi &#61; new BufferedInputStream(fi);GzipCompressorInputStream gzi &#61; new GzipCompressorInputStream(bi);TarArchiveInputStream ti &#61; new TarArchiveInputStream(gzi)) {ArchiveEntry entry;while ((entry &#61; ti.getNextEntry()) !&#61; null) {// 获取解压文件目录&#xff0c;并判断文件是否损坏Path newPath &#61; zipSlipProtect(entry, target);if (entry.isDirectory()) {// 创建解压文件目录Files.createDirectories(newPath);} else {// 再次校验解压文件目录是否存在Path parent &#61; newPath.getParent();if (parent !&#61; null) {if (Files.notExists(parent)) {Files.createDirectories(parent);}}// 将解压文件输入到TarArchiveInputStream&#xff0c;输出到磁盘newPath目录Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING);}}}
}// 判断压缩文件是否被损坏&#xff0c;并返回该文件的解压目录
private Path zipSlipProtect(ArchiveEntry entry,Path targetDir)throws IOException {Path targetDirResolved &#61; targetDir.resolve(entry.getName());Path normalizePath &#61; targetDirResolved.normalize();if (!normalizePath.startsWith(targetDir)) {throw new IOException("压缩文件已被损坏: " &#43; entry.getName());}return normalizePath;
}
转载自:
1.http://www.zimug.com/java/%e4%bd%bf%e7%94%a8java-api%e8%bf%9b%e8%a1%8czip%e9%80%92%e5%bd%92%e5%8e%8b%e7%bc%a9%e6%96%87%e4%bb%b6%e5%a4%b9%e4%bb%a5%e5%8f%8a%e8%a7%a3%e5%8e%8b/.html
2.http://www.zimug.com/java/%e4%bd%bf%e7%94%a8java-api%e8%bf%9b%e8%a1%8ctar-gz%e6%96%87%e4%bb%b6%e5%8f%8a%e6%96%87%e4%bb%b6%e5%a4%b9%e5%8e%8b%e7%bc%a9%e8%a7%a3%e5%8e%8b%e7%bc%a9/.html