java后端文件分片上传,断点续传

java后端文件分片上传,断点续传上面就是实现断点续传的代码,如果有什么不足之处或者觉得缺少了上面,可以直接评论哦,然后我会准时补上,或者给你们解决问题。

Java实现断点分片续传(后端部分)

原由 最近公司在做一个大文件上传的需求,由于使用的框架有限制,所以最大文件不能超过100M,所以如果使用之前的方式直接将整个文件直接上传的话,会直接报错,所以就想到能不能把大文件进行分片,然后逐个文件上传到后端,文件上传完后,后台在进行文件的合并,然后传到指定的服务器中。

解决方法 使用大文件的分片断点续传,也就是前端将一个大文件切割,分成多个小文件,然后依次发送,后台收到请求的时候,将每一个请求发送过来的文件内容生成一个小文件,然后存放在临时目录中,当前端上传完文件后,后端再合并生成的小文件,然后上传到指定服务(ftp或oss等文件存储服务器上)。

实现 1、写一个controller接口(只贴方法)

 /** * * @param request name 文件名, md5 大文件的md5, current 当前分片数, * total 总的分片数 , file 是小文件的数据,这边是前端传过来的blob类型字段 * @return * @throws IOException */
 @RequestMapping(value = "/uploadFile", method = {RequestMethod.POST})
    public R uploadFile(HttpServletRequest request) throws IOException {
        R r = new R();
        String fileName = request.getParameter("name");
        String md5 = request.getParameter("md5");
        String basePath =  request.getSession().getServletContext().getRealPath("/") + "temp" + File.separatorChar + md5;
        File file= new File(basePath);
        if(!file.exists()) {
            file.mkdirs();
        }
        System.out.println("文件目录为:"+ basePath);
        File[] files = file.listFiles();
        Integer current = Integer.parseInt(request.getParameter("current"));
        // 总分片数
        Integer total = Integer.parseInt(request.getParameter("total"));
        int combineFlag = 0;
        // 判断文件是否已经存在相关切片,如果存在跳过已有的切片,开始新的切片上传
        if(files.length >= current) {
        // 文件中切片的总数量和前端传过来切片的数据相同,则直接合并文件
            if(file.length() >= total) {
                String fileUrl = null;
                try {
                    // 合并文件
                    fileUrl = combineFiles(fileName, basePath);
                    if(StringUtils.isNotBlank(fileUrl)) {
                        r.put("filePath", fileUrl);
                        combineFlag = 1;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(combineFlag == 0) {
                        // 合并失败
                        r.put("errMessage", "合并文件失败");
                        r.put("code", 500);
                    } else {
                        r.put("code", 0);
                    }
                    r.put("next", current + 1);
                }
            } else {
                r.put("code", 0);
                r.put("next", files.length + 1);
            }
        } else {

            // 原始文件的大小
            Long size = Long.parseLong(request.getParameter("size"));
            // 当前文件的路径
            String fileNamePath = basePath + File.separatorChar + current;
            OutputStream out = new FileOutputStream(fileNamePath);
            // 获取文件的相关数据,然后写入到文件中
            MultipartFile data = ((MultipartHttpServletRequest) request).getFile("data");
            byte[] bytes = data.getBytes();
            out.write(bytes);
            out.flush();
            out.close();
            // 上传最后一张后,对图片进行合并
            if(current.equals(total)) {
                // 合并操作
                try {
                    String fileUrl = combineFiles(fileName, basePath);
                    if(StringUtils.isNotBlank(fileUrl)) {
                        combineFlag = 1;
                        r.put("filePath", fileUrl);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error(e.toString());
                } finally {
                    if(combineFlag == 0) {
                        // 合并失败
                        r.put("errMessage", "合并文件失败");
                        r.put("code", 500);
                    } else {
                        r.put("code", 0);
                    }
                    r.put("next", current + 1);
                }
            } else {
                r.put("code", 0);
                r.put("next", current + 1);
            }
        }
        return r;
    }
    
    private String combineFiles(String fileName, String basePath) throws Exception {
        int returnFlag = FileUtil.CombineFile(fileName, basePath);
        String fileUrl = null;
        if(returnFlag == 1) {
            // 将文件上传到oss或者是ftp,然后返回一个文件路径
            
            // TODO 当前的代码需要你去补充,就是上传到某个文件服务气的逻辑
            
            fileUrl = ""
            // 将本地的文件删除
            File deleteFile = new File(basePath);
            FileUtil.delTempChild(deleteFile);
        }
        return fileUrl;
    }

文件工具类 fileUtil

public class FileUtil {
/** * 合并文件, * @param tar 合成目标的文件名称 * @param baseFilePath 你要合并哪个文件夹的文件,里面必须是要合并的文件 * @return * @throws Exception */
    public static int CombineFile(String tar, String baseFilePath) throws Exception {
        File dirFile = new File(baseFilePath);
        FileInputStream fis;

        // 一次读取2M数据,将读取到的数据保存到byte字节数组中
        byte buffer[] = new byte[1024 * 1024 * 2];
        int len;
        // 判断file是否为目录
        if(dirFile.isDirectory()) {
            String[] fileNames = dirFile.list();
            FileOutputStream fos = new FileOutputStream(baseFilePath + File.separatorChar + tar);
            // 实现目录自定义排序
            Arrays.sort(fileNames, new StringComparator());
            for (int i = 0;i<fileNames.length ;i++){

                fis = new FileInputStream(baseFilePath + File.separatorChar + fileNames[i]);
                len = 0;
                while ((len = fis.read(buffer)) != -1) {
                    // buffer从指定字节数组写入。buffer:数据中的起始偏移量,len:写入的字数。
                    fos.write(buffer, 0, len);
                }
                fos.flush();
                fis.close();
            }
            fos.close();
        }
        return 1;
    }

    /** * 删除某个文件或者是某个目录 * @param file 文件路径或者是文件夹路径 */
    public static void delTempChild(File file){
        if (file.isDirectory()) {
            // 获取文件夹下所有子文件夹
            String[] children = file.list();
            //递归删除目录中的子目录下
            for (int i=0; i<children.length; i++) {
                delTempChild(new File(file, children[i]));
            }
        }
        // 目录空了,进行删除
        file.delete();
    }
}

比较类

import java.util.Comparator;

/** * @author yanming.gu * @ClassName: StringComparator * @Description * @since 1.0 */
public class StringComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        if (returnDouble(s1) < returnDouble(s2)){
            return -1;
        } else if (returnDouble(s1) > returnDouble(s2)) {
            return 1;
        } else {
            return 0;
        }
    }

    public static double returnDouble(String str){
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<str.length();i++){
            if(Character.isDigit(str.charAt(i))) {
                sb.append(str.charAt(i));
            }  else if(str.charAt(i)=='.'&&i<str.length()-1&&Character.isDigit(str.charAt(i+1))) {
                sb.append(str.charAt(i));
            } else {
                break;
            }
        }
        if(sb.toString().isEmpty()){
            return 0;
        } else {
            return Double.parseDouble(sb.toString());
        }

    }
}

上面就是实现断点续传的代码,如果有什么不足之处或者觉得缺少了上面,可以直接评论哦,然后我会准时补上,或者给你们解决问题。

今天的文章java后端文件分片上传,断点续传分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22492.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注