Java中处理文件和数据时压缩和解压缩是常见的需求,Java IO体系提供了强大的压缩和解压缩流,通过ZipOutputStream、ZipInputStream、GZIPOutputStream和GZIPInputStream等类,我们可以轻松实现文件压缩、归档和解压缩等功能。本文我将深入探讨Java压缩与解压缩流的原理、使用方法及高级应用,帮你全面掌握这一重要技术。
Java提供了多种压缩格式的支持,主要包括:
ZIP是一种常见的归档和压缩格式,支持:
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipExample {
public static void main(String[] args) {
String[] filesToZip = {"file1.txt", "file2.txt", "directory/"};
String zipFileName = "archive.zip";
try (ZipOutputStream zipOut = new ZipOutputStream(
new FileOutputStream(zipFileName))) {
for (String filePath : filesToZip) {
File file = new File(filePath);
if (file.exists()) {
addToZip(file, file.getName(), zipOut);
}
}
System.out.println("ZIP文件创建成功: " + zipFileName);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void addToZip(File file, String entryName, ZipOutputStream zipOut) throws IOException {
if (file.isDirectory()) {
// 处理目录
zipOut.putNextEntry(new ZipEntry(entryName + "/"));
zipOut.closeEntry();
File[] children = file.listFiles();
if (children != null) {
for (File child : children) {
addToZip(child, entryName + "/" + child.getName(), zipOut);
}
}
} else {
// 处理文件
try (FileInputStream fis = new FileInputStream(file)) {
ZipEntry zipEntry = new ZipEntry(entryName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
zipOut.closeEntry();
}
}
}
}
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class UnzipExample {
public static void main(String[] args) {
String zipFileName = "archive.zip";
String destDirectory = "extracted";
try (ZipInputStream zipIn = new ZipInputStream(
new FileInputStream(zipFileName))) {
ZipEntry entry = zipIn.getNextEntry();
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
if (!entry.isDirectory()) {
// 如果条目是文件,解压
extractFile(zipIn, filePath);
} else {
// 如果条目是目录,创建目录
File dir = new File(filePath);
dir.mkdirs();
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
System.out.println("ZIP文件解压成功到: " + destDirectory);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(filePath))) {
byte[] bytesIn = new byte[1024];
int read;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
}
}
GZIP是一种常用的文件压缩格式,特点是:
import java.io.*;
import java.util.zip.GZIPOutputStream;
public class GzipExample {
public static void main(String[] args) {
String sourceFile = "large_file.txt";
String compressedFile = "large_file.txt.gz";
try (FileInputStream fis = new FileInputStream(sourceFile);
GZIPOutputStream gzos = new GZIPOutputStream(
new FileOutputStream(compressedFile))) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
gzos.write(buffer, 0, bytesRead);
}
System.out.println("文件压缩成功: " + compressedFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.util.zip.GZIPInputStream;
public class GunzipExample {
public static void main(String[] args) {
String compressedFile = "large_file.txt.gz";
String decompressedFile = "large_file_uncompressed.txt";
try (GZIPInputStream gzis = new GZIPInputStream(
new FileInputStream(compressedFile));
FileOutputStream fos = new FileOutputStream(decompressedFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = gzis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
System.out.println("文件解压成功: " + decompressedFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ChecksumExample {
public static void main(String[] args) {
String sourceFile = "data.txt";
String zipFile = "data_with_checksum.zip";
try (FileOutputStream fos = new FileOutputStream(zipFile);
CheckedOutputStream cos = new CheckedOutputStream(fos, new Adler32());
ZipOutputStream zos = new ZipOutputStream(cos);
FileInputStream fis = new FileInputStream(sourceFile)) {
// 添加文件到ZIP
ZipEntry entry = new ZipEntry("data.txt");
zos.putNextEntry(entry);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry();
// 获取校验和
long checksum = cos.getChecksum().getValue();
System.out.println("文件校验和: " + checksum);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class SplitZipExample {
private static final int SPLIT_SIZE = 1024 * 1024; // 1MB
public static void main(String[] args) {
String sourceFile = "large_file.dat";
String baseZipName = "split_archive.zip";
try (FileInputStream fis = new FileInputStream(sourceFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
int partNumber = 1;
long currentSize = 0;
ZipOutputStream zos = null;
while ((bytesRead = fis.read(buffer)) != -1) {
// 检查是否需要创建新的分卷
if (zos == null || currentSize + bytesRead > SPLIT_SIZE) {
if (zos != null) {
zos.close();
}
String zipFileName = baseZipName + "." + String.format("%02d", partNumber++);
zos = new ZipOutputStream(new FileOutputStream(zipFileName));
zos.putNextEntry(new ZipEntry("large_file.dat"));
currentSize = 0;
System.out.println("创建分卷: " + zipFileName);
}
zos.write(buffer, 0, bytesRead);
currentSize += bytesRead;
}
if (zos != null) {
zos.closeEntry();
zos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipDirectoryExample {
public static void main(String[] args) {
String sourceDir = "my_directory";
String zipFile = "directory_archive.zip";
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
File directory = new File(sourceDir);
if (directory.exists() && directory.isDirectory()) {
zipDirectory(directory, directory.getName(), zos);
System.out.println("目录压缩成功: " + zipFile);
} else {
System.out.println("源目录不存在或不是目录");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void zipDirectory(File directory, String parentPath, ZipOutputStream zos) throws IOException {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
zipDirectory(file, parentPath + "/" + file.getName(), zos);
} else {
String entryName = parentPath + "/" + file.getName();
ZipEntry zipEntry = new ZipEntry(entryName);
zos.putNextEntry(zipEntry);
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
}
zos.closeEntry();
}
}
}
}
}
在读写压缩流时,始终使用缓冲区可以显著提高性能:
// 使用BufferedInputStream和BufferedOutputStream提高性能
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("source.txt"));
GZIPOutputStream gzos = new GZIPOutputStream(
new BufferedOutputStream(
new FileOutputStream("source.txt.gz")))) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
gzos.write(buffer, 0, bytesRead);
}
}
对于非常大的文件,避免一次性将整个文件加载到内存中:
// 分块处理大文件
try (ZipOutputStream zos = new ZipOutputStream(
new FileOutputStream("large_archive.zip"))) {
ZipEntry entry = new ZipEntry("large_file.dat");
zos.putNextEntry(entry);
try (FileInputStream fis = new FileInputStream("large_file.dat")) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
}
zos.closeEntry();
}
在处理包含中文文件名的ZIP文件时,需要指定正确的字符编码:
// 指定GBK编码处理中文文件名
ZipOutputStream zos = new ZipOutputStream(
new FileOutputStream("chinese_files.zip"),
java.nio.charset.Charset.forName("GBK"));
确保所有流资源被正确关闭,避免资源泄漏:
try (ZipInputStream zis = new ZipInputStream(
new FileInputStream("archive.zip"))) {
// 处理ZIP文件
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
// 处理每个条目
}
} catch (IOException e) {
e.printStackTrace();
}
当ZIP文件中的文件名包含中文时,可能会出现乱码。解决方案是在创建ZipOutputStream
或ZipInputStream
时指定正确的字符编码:
// 读取包含中文文件名的ZIP文件
try (ZipInputStream zis = new ZipInputStream(
new FileInputStream("chinese_archive.zip"),
java.nio.charset.Charset.forName("GBK"))) {
// 处理ZIP文件
}
如果压缩率不理想,可以考虑:
在处理大量数据时,压缩操作可能会成为性能瓶颈。可以考虑:
如果压缩文件损坏,可能的原因包括:
解决方案包括:
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ