美文网首页
基于spring boot 的大文件切片实现

基于spring boot 的大文件切片实现

作者: Poison毒药_d97d | 来源:发表于2022-03-05 09:42 被阅读0次

    前言

      因为公司需要开发一套文件管理系统,传统的上传如果是大文件的话会很慢,因此就使用了分片多线程上传来让其上传速度成倍提升。

    后端

    一、 验证片接口

        /**
         * 校验分片文件是否已经上传
         * @param chunk 分片索引
         * @param chunkSize 分片大小
         * @param guid 文件唯一id
         * @return 分片文件结果
         */
     @PostMapping("checkMd5")
        public AjaxResult checkMd5(@JsonString("chunk") Integer chunk, @JsonString("chunkSize") Integer chunkSize, @JsonString("guid") String guid) {
            //临时文件路径
            String tempPath = SweetNightConfig.getProfile() + File.separator + "temp";
            //要验证的片文件
            File checkFile = new File(tempPath + File.separator + guid + File.separator + chunk);
            AjaxResult ajaxResult = new AjaxResult();
            //比对片文件与其大小
            if (checkFile.exists() && checkFile.length() == chunkSize) {
                ajaxResult.put("ifExist", 1);
            } else {
                ajaxResult.put("ifExist", 0);
            }
            return ajaxResult;
    

    二、片文件上传接口

    /**
         * 片文件上传
         * @param file 片文件
         * @param chunk 片索引
         * @param  guid 文件唯一id
         */
        @PostMapping("upload")
        public void upload(MultipartFile file, Integer chunk, String guid) {
            //临时目录            
            String filePath = SweetNightConfig.getProfile() + File.separator + "temp" + File.separator + guid;
            File tempFile = new File(filePath);
            //如果目录不存在就创建临时目录
            if (!tempFile.exists()) {
                 tempFile.mkdirs();
            }
            //如果未传片索引值就索引就为0
            if (chunk == null) {
                chunk = 0;
            }
            try {
                //块文件
                File dirFile = new File(filePath, String.valueOf(chunk));
                //存储块文件到临时目录
                file.transferTo(dirFile);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    

    三、片合并接口

     /**
         * 合并块
         *
         * @param guid 文件唯一id
         * @param name 合并后的文件名
         */
    
        @PostMapping("combineBlock")
        public void combineBlock(@JsonString("guid") String guid, @JsonString("name") String name) {
            //文件存储目录
            String filePathStr = SweetNightConfig.getUploadPath();
            //临时文件目录
            File tempPath = new File(SweetNightConfig.getProfile() + File.separator + "temp" + File.separator + guid);
            String realFilePath = FileUploadUtils.extractFilename(name);
            //真实目录路径
            filePathStr = filePathStr + "/" + StringUtils.substringBeforeLast(StringUtils.remove(realFilePath, Constants.RESOURCE_PREFIX), "/") + "/";
            File filePath = new File(filePathStr);
            //判断存储目录是否存在不存在先创建
            if (!filePath.exists()) {
                filePath.mkdirs();
            }
            //合并后的文件路径
            File file = new File(filePathStr + File.separator + name);
            FileOutputStream fileOutputStream = null;
            FileChannel fileChannel = null;
            FileChannel fcout = null;
            try {
                fileOutputStream = new FileOutputStream(file, true);
                fcout = fileOutputStream.getChannel();
                //判断临时文件是否存在
                if (tempPath.exists()) {
                    //获取目录下的所有文件
                    File[] tempFiles = tempPath.listFiles();
                    //按文件名进行排序
                    Arrays.sort(tempFiles, (o1, o2) -> {
                        if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {
                            return -1;
                        }
                        if (Integer.parseInt(o1.getName()) == Integer.parseInt(o2.getName())) {
                            return 0;
                        }
                        return 1;
                    });
                    // 分配缓冲区10M
                    ByteBuffer byteBuffer = ByteBuffer.allocate(10 * 1024 * 1024);
                    for (int i = 0; i < tempFiles.length; i++) {
                        FileInputStream fis = new FileInputStream(tempFiles[i]);
                        fileChannel = fis.getChannel();
                        if (fileChannel.read(byteBuffer) != -1) {
                            //缓冲区重设限制缓存区最大可写入数据为当前写入位置,且缓冲区从0开始计算
                            byteBuffer.flip();
                            //判断当前缓存区是否已经写完如果未写完继续写
                            while (byteBuffer.hasRemaining()) {
                                //将片数据写入文件中进行合并
                                fcout.write(byteBuffer);
                            }
                        }
                        //清除写完的缓冲区
                        byteBuffer.clear();
                        //关闭通道
                        fis.close();
                        //删除写完的块
                        tempFiles[i].delete();
    
                    }
                    //合并完成关闭文件流
                    fileOutputStream.close();
                    if (tempPath.isDirectory() && tempPath.exists()) {
                        System.gc();
                        //删除临时文件夹
                        tempPath.delete();
                    }
                    log.info(tempPath.getAbsolutePath());
    
                }
    
            } catch (Exception e) {
                e.printStackTrace();
    
            }
        }
    

    相关文章

      网友评论

          本文标题:基于spring boot 的大文件切片实现

          本文链接:https://www.haomeiwen.com/subject/dmbvrrtx.html