工具类ZipUtils.java代码

2021-10-08 15:09:59 浏览数 (1)

工具类ZipUtils.java代码如下:

代码语言:javascript复制
import com.demo.fileTree.model.FileHandleResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件或者文件夹的压缩和解压缩,详细看java核心技术卷II,P27,
 * 注意,如果是更新项目,要将原来文件夹及文件夹中的内容全部删除,重新生成UUID及文件夹,在这里由于没有到数据库,就不执行这一步了
 *
 * @author xie
 * @version 1.0
 * @Date 2017/5/30
 */
@Service
public class ZipUtils {

    /** 头像图片的放置路径*/
    @Value("${zipPath.home}")
    private String ZipDir;

    /**
     * 获得图片存储路径
     * @return
     */
    public String getZipDir(){
        return ZipDir;
    }

    /**
     * 压缩文件-由于out要在递归外调用,所以封装一个方法
     * 压缩后的压缩文件的路径和命名,比如 File zipFile = new File("C:/home/myblog/project/32位UUID/test.zip"),
     *                 但注意解压缩后的文件夹的名字与压缩文件的名字不一定相同,test.zip只是压缩包的名字,
     *                 在这里我们将test.zip设为fileName.zip,放在32位UUID目录下面,和解压后的项目相同层次,
     *                 下载完成后也不删除,防止多人下载,服务器每次都要压缩文件
     *
     * @param filePath 要压缩的项目的路径
     * @throws IOException
     * @return FileHandleResponse 表示压缩结果实体对象
     */
    public static FileHandleResponse zipFiles(String filePath) throws IOException{
        FileHandleResponse fileHandleResponse = new FileHandleResponse();

        //将压缩文件和原项目放到相同目录下,并且相同命名,除了压缩文件以.zip结尾,但注意filePath以/结尾,要处理一下
        File zipFile = new File(filePath.substring(0,filePath.length()-1) ".zip");
        File noZipFile = new File(filePath);
        if(zipFile.exists()){
            fileHandleResponse.setMessage("压缩文件存在");
        }else if(!noZipFile.exists()){
            fileHandleResponse.setSuccess(0);
            fileHandleResponse.setMessage("请求文件夹或文件不存在!");
            return fileHandleResponse;
        }else{
            try {
                //创建一个将压缩数据写出到指定的OutputStream的ZipOutputStream
                ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
                zipFiles(zipOutputStream, "", noZipFile);
                zipOutputStream.close();
                System.out.println("*****************压缩完毕*******************");
                fileHandleResponse.setMessage("压缩成功");
            } catch (Exception e) {
                fileHandleResponse.setSuccess(0);
                fileHandleResponse.setMessage("服务器异常");
                e.printStackTrace();
                return fileHandleResponse;
            }
        }
        fileHandleResponse.setSuccess(1);
        fileHandleResponse.setUrl(zipFile.getAbsolutePath());
        return fileHandleResponse;
    }

    /**
     * 压缩文件,
     * 如果是目录,则对目录里的文件重新调用ZipFiles方法,一级目录一级目录的压缩
     *
     * @param zipOutputStream 压缩文件输出流
     * @param fileParentPath 压缩文件的上级目录
     * @param srcFiles 要压缩的文件,可以压缩1到多个文件,通过写数组的方式或者一个个写到参数列表里面
     */
    public static void zipFiles(ZipOutputStream zipOutputStream,String fileParentPath,File... srcFiles){
        //将目录中的1个或者多个置换为/,因为在windows目录下,以或者\为文件目录分隔符,linux却是/
        if(fileParentPath!=""){
            fileParentPath = fileParentPath.replaceAll("\ ", "/");
            if(!fileParentPath.endsWith("/")){
                fileParentPath ="/";
            }
        }
        byte[] bytes = new byte[4096];
        try {
            /*
            希望放入zip文件的每一项,都应该创建一个ZipEntry对象,然后将文件名传递给ZipEntry的构造器,它将设置文件日期,解压缩方法等参数,
            并且需要调用putNextEntry方法来开始写出新文件,并将文件数据放松到zip流中,当完成时,需要调用closeEntry方法。所有文件都重复这一过程。
             */

            for(int i=0;i<srcFiles.length;i  ){
                //对于目录,递归
                if(srcFiles[i].isDirectory()){
                    File[] files = srcFiles[i].listFiles();
                    String srcPath = srcFiles[i].getName();
                    srcPath = srcPath.replaceAll("\ ", "/");
                    if(!srcPath.endsWith("/")){
                        srcPath ="/";
                    }
                    zipOutputStream.putNextEntry(new ZipEntry(fileParentPath srcPath));
                    zipFiles(zipOutputStream,fileParentPath srcPath,files);
                }
                //对于文件,发送到ZIP流中,利用4KB的缓冲区,可以考虑使用BufferedInputStream()流过滤器
                else{
                    FileInputStream fileInputStream = new FileInputStream(srcFiles[i]);
                    zipOutputStream.putNextEntry(new ZipEntry(fileParentPath   srcFiles[i].getName()));
                    int len;
                    while((len=fileInputStream.read(bytes))>0){
                        zipOutputStream.write(bytes,0,len);
                    }
                    zipOutputStream.closeEntry();
                    fileInputStream.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解压文件到指定目录
     * @param unZipPath 解压路径,比如C:\home\myblog\project\
     * @param fileName 解压后的文件名,一般命名为项目名,强制要求用户输入,并且保证不为空,
     *                 fileName的上层目录为一个随机生成的32位UUID,以保证项目名重复的依然可以保存到服务器
     * @param multipartFile 上传压缩文件
     *
     * @return FileHandleResponse 表示上传结果实体对象
     */
    @SuppressWarnings("rawtypes")
    public static FileHandleResponse unZipFiles(String unZipPath, String fileName, MultipartFile multipartFile)throws IOException{
        FileHandleResponse fileHandleResponse = new FileHandleResponse();

        String unZipRealPath = unZipPath  UUID.randomUUID().toString().replaceAll("-", "")  "/" fileName   "/";
        //如果保存解压缩文件的目录不存在,则进行创建,并且解压缩后的文件总是放在以fileName命名的文件夹下
        File unZipFile = new File(unZipRealPath);
        if (!unZipFile.exists()) {
            unZipFile.mkdirs();
        }
        //ZipInputStream用来读取压缩文件的输入流
        ZipInputStream zipInputStream = new ZipInputStream(multipartFile.getInputStream());
        //压缩文档中每一个项为一个zipEntry对象,可以通过getNextEntry方法获得,zipEntry可以是文件,也可以是路径,比如abc/test/路径下
        ZipEntry zipEntry;
        try {
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                String zipEntryName = zipEntry.getName();
                //将目录中的1个或者多个置换为/,因为在windows目录下,以或者\为文件目录分隔符,linux却是/
                String outPath = (unZipRealPath   zipEntryName).replaceAll("\ ", "/");
                //判断所要添加的文件所在路径或者
                // 所要添加的路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                //判断文件全路径是否为文件夹,如果是,在上面三行已经创建,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }

                OutputStream outputStream = new FileOutputStream(outPath);
                byte[] bytes = new byte[4096];
                int len;
                //当read的返回值为-1,表示碰到当前项的结尾,而不是碰到zip文件的末尾
                while ((len = zipInputStream.read(bytes)) > 0) {
                    outputStream.write(bytes, 0, len);
                }
                outputStream.close();
                //必须调用closeEntry()方法来读入下一项
                zipInputStream.closeEntry();
            }
            zipInputStream.close();
            fileHandleResponse.setSuccess(1);
            fileHandleResponse.setMessage("解压完毕");
            fileHandleResponse.setUrl((unZipRealPath).replaceAll("\ ", "/"));
            System.out.println("******************解压完毕********************");

        } catch (Exception e) {
            fileHandleResponse.setSuccess(0);
            fileHandleResponse.setMessage("服务器异常");
            e.printStackTrace();
            return fileHandleResponse;
        }
        return fileHandleResponse;
    }
}

0 人点赞