Java压缩技术(七) TAR——Commons实现,tarcommons
分享于 点击 41838 次 点评:208
Java压缩技术(七) TAR——Commons实现,tarcommons
相关链接:Java压缩技术(一) ZLib
Java压缩技术(二) ZIP压缩——Java原生实现
Java压缩技术(三) ZIP解压缩——Java原生实现
Java压缩技术(四)
GZIP——Java原生实现
Java压缩技术(五) GZIP相关——浏览器解析
Java压缩技术(六) BZIP2——Commons实现
Java压缩技术(七) TAR——Commons实现
顺便复习一遍linux命令:
tar cf <file.tar> <file>将由文件<file>创建名为<file.tar>归档文件,同时保留原文件。
tar xf <file.tar>将由归档文件<file.tar>创建名为<file>的文件/目录,同时保留原文件。
对于归档压缩,需分为gzip和bzip2,相应的linux为:
gzip
tar czf <file.tar.gz> <file>将由文件<file>创建名为<file.tar.gz>归档压缩文件,同时保留原文件。
tar xzf <file.tar.gz>将由归档压缩文件<file.tar.gz>创建名为<file>的文件/目录,同时保留原文件。
bzip2
tar cjf <file.tar.bz2> <file>将由文件<file>创建名为<file.tar.bz2>归档压缩文件,同时保留原文件。
tar xjf <file.tar.bz2>将由归档压缩文件<file.tar.bz2>创建名为<file>的文件/目录,同时保留原文件。
今天的主角是Apache Commons Compress下用于Tar操作的三元干将
TarArchiveEntry 类似于Java 原生的ZipEntry,可以理解为Tar归档添加项。
TarArchiveOutputStream Tar归档输出流,用于归档。
TarArchiveInputStream Tar归档输入流,用于解归档。
至于jar,其实现方式与tar非常接近,我就不在这里废话了!
JarArchiveEntry 类似于Java 原生的ZipEntry,可以理解为Jar归档添加项。
JarArchiveOutputStream Jar归档输出流,用于归档。
JarArchiveInputStream Jar归档输入流,用于解归档。
读过Java压缩技术(二)和Java压缩技术(三)会发现,其实Tar的实现与Java原生的Zip实现方式基本上没有差别!
先说归档,依旧需要考虑待归档的对象是文件还是目录:
Java代码
- /**
- * 归档
- *
- * @param srcFile
- * 源路径
- * @param taos
- * TarArchiveOutputStream
- * @param basePath
- * 归档包内相对路径
- * @throws Exception
- */
- private static void archive(File srcFile, TarArchiveOutputStream taos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- archiveDir(srcFile, taos, basePath);
- } else {
- archiveFile(srcFile, taos, basePath);
- }
- }
对于目录,需要区分空目录和包含文件的目录。
如果是空目录,只要简单追加一个归档项(TarArchiveEntry)即可,但注意其名字的结尾需要使用"/"作为区分目录的标识符(String PATH = "/";)。
如果是带有子文件的目录,则需要对其迭代归档:
Java代码
- /**
- * 目录归档
- *
- * @param dir
- * @param taos
- * TarArchiveOutputStream
- * @param basePath
- * @throws Exception
- */
- private static void archiveDir(File dir, TarArchiveOutputStream taos,
- String basePath) throws Exception {
- File[] files = dir.listFiles();
- if (files.length < 1) {
- TarArchiveEntry entry = new TarArchiveEntry(basePath
- + dir.getName() + PATH);
- taos.putArchiveEntry(entry);
- taos.closeArchiveEntry();
- }
- for (File file : files) {
- // 递归归档
- archive(file, taos, basePath + dir.getName() + PATH);
- }
- }
最后,来看归档操作:
Java代码
- /**
- * 数据归档
- *
- * @param data
- * 待归档数据
- * @param path
- * 归档数据的当前路径
- * @param name
- * 归档文件名
- * @param taos
- * TarArchiveOutputStream
- * @throws Exception
- */
- private static void archiveFile(File file, TarArchiveOutputStream taos,
- String dir) throws Exception {
- TarArchiveEntry entry = new TarArchiveEntry(dir + file.getName());
- entry.setSize(file.length());
- taos.putArchiveEntry(entry);
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- taos.write(data, 0, count);
- }
- bis.close();
- taos.closeArchiveEntry();
- }
注意执行归档操作后,执行closeArchiveEntry()方法。
Tar解归档,与Zip解压相似,一样要遍历获得归档项:
Java代码
- /**
- * 文件 解归档
- *
- * @param destFile
- * 目标文件
- * @param tais
- * ZipInputStream
- * @throws Exception
- */
- private static void dearchive(File destFile, TarArchiveInputStream tais)
- throws Exception {
- TarArchiveEntry entry = null;
- while ((entry = tais.getNextTarEntry()) != null) {
- // 文件
- String dir = destFile.getPath() + File.separator + entry.getName();
- File dirFile = new File(dir);
- // 文件检查
- fileProber(dirFile);
- if (entry.isDirectory()) {
- dirFile.mkdirs();
- } else {
- dearchiveFile(dirFile, tais);
- }
- }
- }
最后,进行解归档:
Java代码
- /**
- * 文件解归档
- *
- * @param destFile
- * 目标文件
- * @param tais
- * TarArchiveInputStream
- * @throws Exception
- */
- private static void dearchiveFile(File destFile, TarArchiveInputStream tais)
- throws Exception {
- BufferedOutputStream bos = new BufferedOutputStream(
- new FileOutputStream(destFile));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = tais.read(data, 0, BUFFER)) != -1) {
- bos.write(data, 0, count);
- }
- bos.close();
- }
文件探针用于构建父目录:
Java代码
- /**
- * 文件探针
- *
- * <pre>
- * 当父目录不存在时,创建目录!
- * </pre>
- *
- * @param dirFile
- */
- private static void fileProber(File dirFile) {
- File parentFile = dirFile.getParentFile();
- if (!parentFile.exists()) {
- // 递归寻找上级目录
- fileProber(parentFile);
- parentFile.mkdir();
- }
- }
给出完整实现:
Java代码
- /**
- * 2010-4-20
- */
- package org.zlex.commons.compress;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
- import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
- import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
- /**
- * TAR工具
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
- * @since 1.0
- */
- public abstract class TarUtils {
- private static final String BASE_DIR = "";
- // 符号"/"用来作为目录标识判断符
- private static final String PATH = "/";
- private static final int BUFFER = 1024;
- private static final String EXT = ".tar";
- /**
- * 归档
- *
- * @param srcPath
- * @param destPath
- * @throws Exception
- */
- public static void archive(String srcPath, String destPath)
- throws Exception {
- File srcFile = new File(srcPath);
- archive(srcFile, destPath);
- }
- /**
- * 归档
- *
- * @param srcFile
- * 源路径
- * @param destPath
- * 目标路径
- * @throws Exception
- */
- public static void archive(File srcFile, File destFile) throws Exception {
- TarArchiveOutputStream taos = new TarArchiveOutputStream(
- new FileOutputStream(destFile));
- archive(srcFile, taos, BASE_DIR);
- taos.flush();
- taos.close();
- }
- /**
- * 归档
- *
- * @param srcFile
- * @throws Exception
- */
- public static void archive(File srcFile) throws Exception {
- String name = srcFile.getName();
- String basePath = srcFile.getParent();
- String destPath = basePath + name + EXT;
- archive(srcFile, destPath);
- }
- /**
- * 归档文件
- *
- * @param srcFile
- * @param destPath
- * @throws Exception
- */
- public static void archive(File srcFile, String destPath) throws Exception {
- archive(srcFile, new File(destPath));
- }
- /**
- * 归档
- *
- * @param srcPath
- * @throws Exception
- */
- public static void archive(String srcPath) throws Exception {
- File srcFile = new File(srcPath);
- archive(srcFile);
- }
- /**
- * 归档
- *
- * @param srcFile
- * 源路径
- * @param taos
- * TarArchiveOutputStream
- * @param basePath
- * 归档包内相对路径
- * @throws Exception
- */
- private static void archive(File srcFile, TarArchiveOutputStream taos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- archiveDir(srcFile, taos, basePath);
- } else {
- archiveFile(srcFile, taos, basePath);
- }
- }
- /**
- * 目录归档
- *
- * @param dir
- * @param taos
- * TarArchiveOutputStream
- * @param basePath
- * @throws Exception
- */
- private static void archiveDir(File dir, TarArchiveOutputStream taos,
- String basePath) throws Exception {
- File[] files = dir.listFiles();
- if (files.length < 1) {
- TarArchiveEntry entry = new TarArchiveEntry(basePath
- + dir.getName() + PATH);
- taos.putArchiveEntry(entry);
- taos.closeArchiveEntry();
- }
- for (File file : files) {
- // 递归归档
- archive(file, taos, basePath + dir.getName() + PATH);
- }
- }
- /**
- * 数据归档
- *
- * @param data
- * 待归档数据
- * @param path
- * 归档数据的当前路径
- * @param name
- * 归档文件名
- * @param taos
- * TarArchiveOutputStream
- * @throws Exception
- */
- private static void archiveFile(File file, TarArchiveOutputStream taos,
- String dir) throws Exception {
- /**
- * 归档内文件名定义
- *
- * <pre>
- * 如果有多级目录,那么这里就需要给出包含目录的文件名
- * 如果用WinRAR打开归档包,中文名将显示为乱码
- * </pre>
- */
- TarArchiveEntry entry = new TarArchiveEntry(dir + file.getName());
- entry.setSize(file.length());
- taos.putArchiveEntry(entry);
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- taos.write(data, 0, count);
- }
- bis.close();
- taos.closeArchiveEntry();
- }
- /**
- * 解归档
- *
- * @param srcFile
- * @throws Exception
- */
- public static void dearchive(File srcFile) throws Exception {
- String basePath = srcFile.getParent();
- dearchive(srcFile, basePath);
- }
- /**
- * 解归档
- *
- * @param srcFile
- * @param destFile
- * @throws Exception
- */
- public static void dearchive(File srcFile, File destFile) throws Exception {
- TarArchiveInputStream tais = new TarArchiveInputStream(
- new FileInputStream(srcFile));
- dearchive(destFile, tais);
- tais.close();
- }
- /**
- * 解归档
- *
- * @param srcFile
- * @param destPath
- * @throws Exception
- */
- public static void dearchive(File srcFile, String destPath)
- throws Exception {
- dearchive(srcFile, new File(destPath));
- }
- /**
- * 文件 解归档
- *
- * @param destFile
- * 目标文件
- * @param tais
- * ZipInputStream
- * @throws Exception
- */
- private static void dearchive(File destFile, TarArchiveInputStream tais)
- throws Exception {
- TarArchiveEntry entry = null;
- while ((entry = tais.getNextTarEntry()) != null) {
- // 文件
- String dir = destFile.getPath() + File.separator + entry.getName();
- File dirFile = new File(dir);
- // 文件检查
- fileProber(dirFile);
- if (entry.isDirectory()) {
- dirFile.mkdirs();
- } else {
- dearchiveFile(dirFile, tais);
- }
- }
- }
- /**
- * 文件 解归档
- *
- * @param srcPath
- * 源文件路径
- *
- * @throws Exception
- */
- public static void dearchive(String srcPath) throws Exception {
- File srcFile = new File(srcPath);
- dearchive(srcFile);
- }
- /**
- * 文件 解归档
- *
- * @param srcPath
- * 源文件路径
- * @param destPath
- * 目标文件路径
- * @throws Exception
- */
- public static void dearchive(String srcPath, String destPath)
- throws Exception {
- File srcFile = new File(srcPath);
- dearchive(srcFile, destPath);
- }
- /**
- * 文件解归档
- *
- * @param destFile
- * 目标文件
- * @param tais
- * TarArchiveInputStream
- * @throws Exception
- */
- private static void dearchiveFile(File destFile, TarArchiveInputStream tais)
- throws Exception {
- BufferedOutputStream bos = new BufferedOutputStream(
- new FileOutputStream(destFile));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = tais.read(data, 0, BUFFER)) != -1) {
- bos.write(data, 0, count);
- }
- bos.close();
- }
- /**
- * 文件探针
- *
- * <pre>
- * 当父目录不存在时,创建目录!
- * </pre>
- *
- * @param dirFile
- */
- private static void fileProber(File dirFile) {
- File parentFile = dirFile.getParentFile();
- if (!parentFile.exists()) {
- // 递归寻找上级目录
- fileProber(parentFile);
- parentFile.mkdir();
- }
- }
- }
最后给出测试用例:
Java代码
- /**
- * 2010-4-20
- */
- package org.zlex.commons.compress;
- import static org.junit.Assert.*;
- import java.io.DataInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import org.junit.Before;
- import org.junit.Test;
- /**
- * Tar测试
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
- * @since 1.0
- */
- public class TarUtilsTest {
- private String inputStr;
- private String name = "data.xml";
- @Before
- public void before() {
- StringBuilder sb = new StringBuilder();
- sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
- sb.append("\r\n");
- sb.append("<dataGroup>");
- sb.append("\r\n\t");
- sb.append("<dataItem>");
- sb.append("\r\n\t\t");
- sb.append("<data>");
- sb.append("Test");
- sb.append("</data>");
- sb.append("\r\n\t");
- sb.append("<dataItem>");
- sb.append("\r\n");
- sb.append("</dataGroup>");
- inputStr = sb.toString();
- }
- @Test
- public void testArchiveFile() throws Exception {
- byte[] contentOfEntry = inputStr.getBytes();
- String path = "d:/" + name;
- FileOutputStream fos = new FileOutputStream(path);
- fos.write(contentOfEntry);
- fos.flush();
- fos.close();
- TarUtils.archive(path);
- TarUtils.dearchive(path + ".tar");
- File file = new File(path);
- FileInputStream fis = new FileInputStream(file);
- DataInputStream dis = new DataInputStream(fis);
- byte[] data = new byte[(int) file.length()];
- dis.readFully(data);
- fis.close();
- String outputStr = new String(data);
- assertEquals(inputStr, outputStr);
- }
- @Test
- public void testArchiveDir() throws Exception {
- String path = "d:/fd";
- TarUtils.archive(path);
- TarUtils.dearchive(path + ".tar", "d:/fds");
- }
- }
执行代码,来看下效果:
这是原始文件。
这是归档后的文件。
注意红框,这里没有经过任何压缩!
除了tar、zip,其实还有很多归档算法,如ar、jar、cpio。其实现方式,与上述内容较为接近。
至于压缩成*.tar.gz、*.tar.bz2,请朋友们参照前几篇内容!
相关文章
- 暂无相关文章
用户点评