IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 如何将服务器上的文件_按自定义的层级关系_进行压缩并下载 -> 正文阅读

[系统运维]如何将服务器上的文件_按自定义的层级关系_进行压缩并下载

这两天接了一个需求,让我把服务器上无序的图片资源按 班级、姓名 目录结构进行压缩

任务解释
场景老师发布某活动(对应activityId),学生可以在上面提交作品(workId)
每个作品可以对应多张图片(资源路径List<String>)
需求传入一个指定的活动activityId,将这个活动下的作品,分班级、姓名 作为层级关系打包至zip压缩包中
要点1 :自定义压缩包的层级关系主要是要自定义层级关系,因此需要在DAO层得到的dto中就开始结构的设计以方便遍历
当时卡在不知道如何指定一个层级关系,后来不断尝试发现ZipOutPutStream中的putZipEntry()形参中可以通过 dir1//dir2//picture.png来指定生成的zip中的层级关系但是前提是,整个过程完成之前不能关闭流
要点2:直接把生成的结果放入响应体,不存入服务器因为作品时常变动,生成的zip不一定是最终的,所以不能放入服务器。因此直接放入HttpServletResponse.getOutPutStream()中
省略一些步骤需求中有大量的业务相关,十分繁琐的步骤,因此这个帖子直接贴一个demo(在自己的电脑上做一个demo)
注意这个demo不是现成的工具类,使用时需要自己改造

1.压缩流ZipOutPutStream介绍

主要是介绍两个重要API

  • putNextEntry( ZipEntry entry),在流结束之前,存入下一个要加入压缩包的文件(不是文件夹),并命名(zip包中该文件的名字)
  • new ZipEntry(String name),指定下一个压缩文件的名字

大概的使用流程是:

  File zip = new File(输出路径);//输出路径
  FileOutputStream zipFOS = new FileOutputStream(zip);//输出流
  ZipOutputStream zipZipOS = new ZipOutputStream(zipFOS);//压缩流
  BufferedOutputStream zipBufferOS = new BufferedOutputStream(zipZipOS);//缓冲流

虽然最外层是缓冲流,但上面两个API还是针对于压缩流的对象进行操作

zipZipOS.putNextEntry(new ZipEntry("一年级1班\\张三\\1.png"));
zipZipOS.putNextEntry(new ZipEntry("一年级1班\\李四\\2.png"));
zipZipOS.putNextEntry(new ZipEntry("一年级2班\\王八\\3.png"));

然后用最外层的缓冲流进行读写

BufferedInputStream fileBIS = new BufferedInputStream( //缓冲输入流
                          new FileInputStream(
                          new File(资源路径));
  len = 0;
  while( (len = fileBIS.read(buffer)) != -1){
  zipBufferOS.write(buffer);
  }

最后关闭 最外层流,就可以了(关闭最外层流的时候内层会自动优先关闭,只需要写一遍)

  fileBIS.close(); //最外层缓冲输入流,调用几次就开 关 几次
  zipBufferOS.close();//最外层缓冲输出流,最后关闭一次即可

2.demo演示

看main方法可知,将我电脑上的无序资源,前三个放在一年级1班,后三个放在二年级2班

这里的演示为了更清晰,没有使用try-catch

2.1控制层

@RestController
@RequestMapping("download")
public class ToZipController {

  @Autowired
  ZipService zipService;//获取dots 处理文件压缩

  @GetMapping("/zip")
  public String getZipFromServerToResponse(
                                HttpServletResponse res) throws IOException {

    List<Dto> dtoList = zipService.getDtoList();

	//在处理输出流之前添加   
	//res.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("活动测试") + ".zip");
	//可以设置文件输出的名字以及格式,测试后适配所有主流浏览器
    zipService.doCompressToResponse(dtoList,res.getOutputStream());

    
    return "succeed";
	  }


  @GetMapping("/zip/server")
  public String getZipFromServerToServer(HttpServletResponse res) throws IOException{

    List<Dto> dtoList = zipService.getDtoList();
    zipService.doCompressToDestZip(dtoList,"D:\\pic_test\\destzip.zip");
    return "succeed";
  }

2.2Dto实体类

@Data
@AllArgsConstructor
public class Dto {

private String activityId;//活动id
private String activityName;//活动名称
private String className;//班级名称
private String studentName;//学生姓名
private String url;//图片地址

}

2.3业务层

2.3.1模拟获取List<Dto>

  /**
    *   获取将需要被压缩的图片的基本信息
   */
  public List<Dto> getDtoList() throws IOException {
    ArrayList<Dto> dtos = new ArrayList<>();
    dtos.add(new Dto("11","分享你的假期生活","一年级1班","张三","D:\\pic_test\\1.png"));
    dtos.add(new Dto("11","分享你的假期生活","一年级1班","张三","D:\\pic_test\\2.png"));

    dtos.add(new Dto("11","分享你的假期生活","一年级1班","李四","D:\\pic_test\\3.png"));

    dtos.add(new Dto("11","分享你的假期生活","九年级2班","王八","D:\\pic_test\\4.png"));
    dtos.add(new Dto("11","分享你的假期生活","九年级2班","王八","D:\\pic_test\\5.png"));
    dtos.add(new Dto("11","分享你的假期生活","九年级2班","王八","D:\\pic_test\\6.png"));
    return dtos;
  }

2.3.2压缩方法1:写入HttpServletResponse

  /**  方案1:写入response,不指定输出zip的位置
   *   通过todoList中的信息来分层级压缩,放入res.outPutStream()
   */
  public void doCompressToResponse(List<Dto> todoList, OutputStream os) throws IOException{
    System.out.println(111);
      //1.开启流
    ZipOutputStream zipOS = new ZipOutputStream(os);
    BufferedOutputStream bufZipOS = new BufferedOutputStream(zipOS);

      //2.遍历
    Iterator<Dto> iterator = todoList.iterator();
    while(iterator.hasNext()){
      Dto next = iterator.next();
        //2.1下一个待压缩的元素

      /**
       *
       * 根据业务需要,可以针对文件生成的名字进行修改
       *
       */
      zipOS.putNextEntry(new ZipEntry(next.getActivityName()+"\\"+
                                            next.getClassName()+"\\"+
                                            next.getStudentName()+"\\"+
                                      UUID.randomUUID().toString()+".png"
          ));


        //2.2获取输入流  (缓冲)   根据url
      BufferedInputStream fileBIS = new BufferedInputStream(
          new FileInputStream(   //根据业务,如果允许,可以直接传byte[]
              new File(next.getUrl())));

        //2.3写入
      int len = 0;
      while( (len = fileBIS.read(BUFFER)) != -1){//fileBIS读取流到BUFFER数组
        bufZipOS.write(BUFFER);   //BUFFER数组内容写入到bufZipOS中
      }

        //2.4每次写完之后一定要flush刷新
      bufZipOS.flush();
        //2.4关闭每次的输入流
      fileBIS.close();
    }


      //3.遍历结束,全部完成,此时关闭zip流
      bufZipOS.close();//关最外层即可
  }

需要十分注意的是:

  • 遍历循环时,每次开启、关闭一个输入流
  • 当所有元素遍历结束之后,才会关闭输出流
  • 遍历时,每次读取一个文件都需要刷新输出流,否则会导致内部文件无法打开

2.3.3压缩方法2:指定位置持久化

  • 此接口可以通过返回一个url,让前端异步获取资源

  • 方案1 2 其实大体上差不多,区别在于输出流的指定,一个是直接res.outPutStream() 一个是通过new File()来持久化

       /**
         *   方案2:形参是一个地址,直接持久化
         *   而不是写入response响应
          *
         */
        public void doCompressToDestZip(List<Dto> todoList, String destZip) throws IOException{
          //1.开启流
          File                 file     = new File(destZip);
          FileOutputStream      fIS = new FileOutputStream(file);
          ZipOutputStream zipOS = new ZipOutputStream(fIS);
          BufferedOutputStream bufZipOS = new BufferedOutputStream(zipOS);
      
          //2.遍历
          Iterator<Dto> iterator = todoList.iterator();
          while(iterator.hasNext()){
            Dto next = iterator.next();
      
            /**
             *
             * 根据业务需要,可以针对文件生成的名字进行修改
             *
             */
      
            //2.1下一个待压缩的元素
            zipOS.putNextEntry(new ZipEntry(next.getActivityName()+"\\"+
                next.getClassName()+"\\"+
                next.getStudentName()+"\\"+
                UUID.randomUUID().toString()+".png"
            ));
      
            //2.2获取输入流  (缓冲)   根据url
            BufferedInputStream fileBIS = new BufferedInputStream(
                new FileInputStream(  //根据业务,如果允许,可以直接传byte[]
                    new File(next.getUrl())));
      
            //2.3写入
            int len = 0;
            while( (len = fileBIS.read(BUFFER)) != -1){//fileBIS读取流到BUFFER数组
              bufZipOS.write(BUFFER);   //BUFFER数组内容写入到bufZipOS中
            }
            //2.4关闭遍历时每次的输入流
            fileBIS.close();
          }
      
            //3.遍历结束,全部完成,此时关闭zip流
            bufZipOS.close();//关最外层即可
      
      }
    
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 17:01:55  更:2022-07-17 17:05:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 18:16:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码