文件压缩与解压缩

文件压缩

package zt.o.commoncommon.utils;

import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
    private static final int  BUFFER_SIZE = 2 * 1024;

    /**
      * 压缩成ZIP 方法1
      * @param srcDir 压缩文件夹路径
      * @param out    压缩文件输出流
      * @param KeepDirStructure  是否保留原来的目录结构,true:保留目录结构;
      *                          false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
      * @throws RuntimeException 压缩失败会抛出运行时异常

      */
     public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
             throws RuntimeException{
         long start = System.currentTimeMillis();
         ZipOutputStream zos = null ;

         try {
             zos = new ZipOutputStream(out);
             File sourceFile = new File(srcDir);
             compress(sourceFile,zos,sourceFile.getName(),KeepDirStructure);

             long end = System.currentTimeMillis();
             System.out.println("压缩完成,耗时:" + (end - start) +" ms");
         } catch (Exception e) {
             throw new RuntimeException("zip error from ZipUtils",e);
         }finally{
             if(zos != null){
                 try {
                     zos.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
     }

     /**
      * 压缩成ZIP 方法2
      * @param srcFiles 需要压缩的文件列表
      * @param out           压缩文件输出流
      * @throws RuntimeException 压缩失败会抛出运行时异常

      */

     public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {
         long start = System.currentTimeMillis();
         ZipOutputStream zos = null ;
         try {
             zos = new ZipOutputStream(out);
             for (File srcFile : srcFiles) {
                 byte[] buf = new byte[BUFFER_SIZE];
                 zos.putNextEntry(new ZipEntry(srcFile.getName()));
                 int len;
                 FileInputStream in = new FileInputStream(srcFile);
                 while ((len = in.read(buf)) != -1){
                     zos.write(buf, 0, len);
                 }
                 zos.closeEntry();
                 in.close();
             }
             long end = System.currentTimeMillis();
             System.out.println("压缩完成,耗时:" + (end - start) +" ms");
         } catch (Exception e) {
             throw new RuntimeException("zip error from ZipUtils",e);
         }finally{
             if(zos != null){
                 try {
                     zos.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
     }

     /**
      * 递归压缩方法
      * @param sourceFile 源文件
      * @param zos        zip输出流
      * @param name       压缩后的名称
      * @param KeepDirStructure  是否保留原来的目录结构,true:保留目录结构;
      *  false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
      * @throws Exception
      */

     private static void compress(File sourceFile, ZipOutputStream zos, String name,
                                  boolean KeepDirStructure) throws Exception{
         byte[] buf = new byte[BUFFER_SIZE];
         if(sourceFile.isFile()){
             // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
             zos.putNextEntry(new ZipEntry(name));
             // copy文件到zip输出流中
             int len;
             FileInputStream in = new FileInputStream(sourceFile);
             while ((len = in.read(buf)) != -1){
                 zos.write(buf, 0, len);
             }
             // Complete the entry
             zos.closeEntry();
             in.close();
         } else {
             File[] listFiles = sourceFile.listFiles();
             if(listFiles == null || listFiles.length == 0){
                 // 需要保留原来的文件结构时,需要对空文件夹进行处理
                 if(KeepDirStructure){
                     // 空文件夹的处理
                     zos.putNextEntry(new ZipEntry(name + File.separator));
                     // 没有文件,不需要文件的copy
                     zos.closeEntry();
                 }
             }else {
                 for (File file : listFiles) {
                     // 判断是否需要保留原来的文件结构
                     if (KeepDirStructure) {
                         // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                         // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                         compress(file, zos, name + File.separator + file.getName(),KeepDirStructure);
                     } else {
                         compress(file, zos, file.getName(),KeepDirStructure);
                     }
                 }
             }
         }
     }

     public static void main(String args[]) throws IOException {
         /** 测试压缩方法1  */
         File file = new File("C:\\Users\\xieyong23482\\Desktop\\test.zip");
         if (!file.exists()){
             file.createNewFile();
         }
         FileOutputStream fos1 = new FileOutputStream(file);

         ZipUtils.toZip("C:\\Users\\xieyong23482\\Desktop\\档案(可自定义名称)", fos1,true);
     }
}

二、注意事项
    写该工具类时,有些注意事项说一下:
        (1)支持选择是否保留原来的文件目录结构,如果不保留,那么空文件夹直接不用处理。
        (1)碰到空文件夹时,如果需要保留目录结构,则直接添加个ZipEntry就可以了,不过就是这个entry的名字后面需要带上一斜杠(/)表示这个是目录。
        (2)递归时,不需要把zip输出流关闭,zip输出流的关闭应该是在调用完递归方法后面关闭
        (3)递归时,如果是个文件夹且需要保留目录结构,那么在调用方法压缩他的子文件时,需要把文件夹的名字加一斜杠给添加到子文件名字前面,这样压缩后才有多级目录。
Web用法

  这个工具类在web项目中的使用场景就是多文件下载,我就简单说个下载多个excel表格的案例吧。
    代码中的步骤为:
        (1)创建一个临时文件夹
        (2)将要下载的文件生成至该临时文件夹内
        (3)当所有文件生成完后,获取HttpServletResponse获取设置下载的header
        (4)调用工具类的方法,传入上面生成的临时文件夹路径及response获取的输出流;这样就下载出来zip包了
        (5)递归删除掉上面生成的临时文件夹和文件

    下面为一个示例代码的代码片段,不是完整代码,简单看一下代码中的步骤


    if(userList.size() > 0){

        /** 下面为下载zip压缩包相关流程 */

        HttpServletRequest request = ServletActionContext.getRequest();

        FileWriter writer;

        /** 1.创建临时文件夹  */

        String rootPath = request.getSession().getServletContext().getRealPath("/");

        File temDir = new File(rootPath + "/" + UUID.randomUUID().toString().replaceAll("-", ""));

        if(!temDir.exists()){

            temDir.mkdirs();

        }

        

        /** 2.生成需要下载的文件,存放在临时文件夹内 */

        // 这里我们直接来10个内容相同的文件为例,但这个10个文件名不可以相同

        for (int i = 0; i < 10; i++) {

            dataMap.put("userList", userList);

            Map<String, String> endMap = new HashMap<>();

            endMap.put("user", "老王");

            endMap.put("time", "2017-10-10 10:50:55");

            dataMap.put("endMap", endMap);

            Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);

            cfg.setServletContextForTemplateLoading(ServletActionContext.getServletContext(), "/ftl");

            Template template = cfg.getTemplate("exportExcel.ftl");

            writer = new FileWriter(temDir.getPath()+"/excel"+ i +".xls");

            template.process(dataMap, writer);

            writer.flush();

            writer.close();

        }

        

        /** 3.设置response的header */

        HttpServletResponse response = ServletActionContext.getResponse();

        response.setContentType("application/zip");

        response.setHeader("Content-Disposition", "attachment; filename=excel.zip");  

       

        /** 4.调用工具类,下载zip压缩包 */

        // 这里我们不需要保留目录结构

        ZipUtils.toZip(temDir.getPath(), response.getOutputStream(),false);

        

        /** 5.删除临时文件和文件夹 */

        // 这里我没写递归,直接就这样删除了

        File[] listFiles = temDir.listFiles();

        for (int i = 0; i < listFiles.length; i++) {

            listFiles[i].delete();

        }

        temDir.delete();

    }

解压缩

package zt.o.commoncommon.utils;

import de.innosystec.unrar.Archive;
import de.innosystec.unrar.NativeStorage;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Expand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zt.o.commoncommon.exception.CustomerException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DeCompressUtil {

private final static Logger logger = LoggerFactory.getLogger(DeCompressUtil.class);

/**
* 解压zip文件
* @param sourceZip 被解压的文件
* @param destDir 解压到指定的目录
*/
private static void unzip(File sourceZip,File destDir){
try{
Project p = new Project();
Expand e = new Expand();
e.setProject(p);
e.setSrc(sourceZip);
e.setOverwrite(false);
e.setDest(destDir);
/*
ant下的zip工具默认压缩编码为UTF-8编码,
而winRAR软件压缩是用的windows默认的GBK或者GB2312编码
所以解压缩时要制定编码格式
*/
e.setEncoding("gbk");
e.execute();
}catch(Exception e){
logger.info("ZIP文件解压失败,错误信息:"+e.getMessage()+e.getStackTrace()[0]);
CustomerException customerException = new CustomerException("-1");
customerException.setErrorMessage("ZIP文件解压失败");
throw customerException;
}
}

/**
* 解压缩rar文件
* @param sourceRar 被解压缩文件
* @param destDir 解压缩到指定的目录
*/
private static void unrar(File sourceRar, File destDir){
Archive archive = null;
FileOutputStream fos = null;
String destFile = null;
String compressFileName;
logger.info("sourceRar="+sourceRar+"destDir"+destDir+"Starting...");
try {
archive = new Archive(new NativeStorage(sourceRar));
FileHeader fh = archive.nextFileHeader();
File destFileName = null;
//现在就按null来判断
if (fh == null){
CustomerException customerException = new CustomerException("-1");
customerException.setErrorMessage("系统不支持RAR5压缩格式,请用ZIP或者低版本RAR压缩格式进行导入");
throw customerException;
}
while (fh != null) {
//通过中文的形式获取
compressFileName = fh.getFileNameW().trim();
//如果不包含中文
if(!existZH(compressFileName)){
compressFileName = fh.getFileNameString().trim();
}
if(File.separator.equals("/")){
//非windows系统
destFile = destDir.getAbsolutePath()+File.separator+compressFileName.replace("\\", "/");
}else {
//Windows系统
destFile = destDir.getAbsolutePath()+File.separator+compressFileName.replace("/", "\\");
}
logger.info("解压文件名(compressFileName) is "+compressFileName+";target path: "+destFile);
destFileName = new File(destFile);
//如果是文件目录
if (fh.isDirectory()) {
if (!destFileName.exists()) {
destFileName.mkdirs();
}
fh = archive.nextFileHeader();
continue;
}
//创建父目录
if (!destFileName.getParentFile().exists()) {
destFileName.getParentFile().mkdirs();
}
fos = new FileOutputStream(destFileName);
archive.extractFile(fh, fos);
fos.close();
fos = null;
fh = archive.nextFileHeader();
}

archive.close();
archive = null;
logger.info("sourceRar="+sourceRar+"destDir"+destDir+"Finished !");
} catch (Exception ex) {
logger.info("RAR文件解压失败,错误信息:"+ex.getMessage()+ex.getStackTrace()[0]);
CustomerException customerException = new CustomerException("-1");
if (ex instanceof RarException ) {
if ( ex.getMessage() != null && ex.getMessage().contains("badRarArchive") ) {
customerException.setErrorMessage("系统不支持RAR5压缩格式,请用ZIP或者低版本RAR压缩格式进行导入");
throw customerException;
} else {
customerException.setErrorMessage("RAR文件解压失败");
throw customerException;
}
}else if(ex instanceof CustomerException){
customerException.setErrorMessage(((CustomerException) ex).getErrorMessage());
throw customerException;
}else{
customerException.setErrorMessage("RAR文件解压失败");
throw customerException;
}
} finally {
if (fos != null) {
try {
fos.close();
fos = null;
} catch (Exception e) {
e.printStackTrace();
}
}
if (archive != null) {
try {
archive.close();
archive = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

/**
* 采用命令行方式解压文件
* @param zipFile 压缩文件
* @param destDir 解压结果路径
* @return
*/
public static boolean realExtract(String sourceFile, String destDir) {
// 解决路径中存在/..格式的路径问题
destDir = new File(destDir).getAbsoluteFile().getAbsolutePath();
while(destDir.contains("..")) {
String[] sepList = destDir.split("\\\\");
destDir = "";
for (int i = 0; i < sepList.length; i++) {
if(!"..".equals(sepList[i]) && i < sepList.length -1 && "..".equals(sepList[i+1])) {
i++;
} else {
destDir += sepList[i] + File.separator;
}
}
}

// 获取WinRAR.exe的路径
String classPath = "";
try {
classPath = Thread.currentThread().getContextClassLoader().getResource("").toURI().getPath();
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
// 兼容main方法执行和javaweb下执行
String winrarPath = (classPath.indexOf("WEB-INF") > -1 ? classPath.substring(0, classPath.indexOf("WEB-INF")) :
classPath.substring(0, classPath.indexOf("classes"))) + "/WinRAR/WinRAR.exe";
winrarPath = new File(winrarPath).getAbsoluteFile().getAbsolutePath();

boolean bool = false;
File zipFile = new File(sourceFile);
if (!zipFile.exists()) {
return false;
}

// 开始调用命令行解压,参数-o+是表示覆盖的意思
String cmd = winrarPath + " X -o+ " + zipFile + " " + destDir;
System.out.println(cmd);
try {
Process proc = Runtime.getRuntime().exec(cmd);
if (proc.waitFor() != 0) {
if (proc.exitValue() == 0) {
bool = false;
}
} else {
bool = true;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("解压" + (bool ? "成功" : "失败"));
return bool;
}

/**
*
* @param sourceFile 被解压缩文件
* @param destDir 解压缩到指定目录
*/
public static void deCompress(String sourceFile,String destDir) {
/*//保证文件夹路径最后是"/"或者"\"
char lastChar = destDir.charAt(destDir.length()-1);
if(lastChar!='/'&& lastChar!='\\'){
destDir += File.separator;
}*/
//根据类型,进行相应的解压缩
String type = sourceFile.substring(sourceFile.lastIndexOf(".")+1);
if(type.equals("zip")){
DeCompressUtil.unzip(new File(sourceFile), new File(destDir));
}else if(type.equals("rar")){
DeCompressUtil.unrar(new File(sourceFile), new File(destDir));
}
}

public static boolean existZH(String str) {
String regEx = "[\\u4e00-\\u9fa5]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
while (m.find()) {
return true;
}
return false;
}


}
发布了115 篇原创文章 · 获赞 57 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_35211818/article/details/104183282
今日推荐