Java实现文件分片上传

这篇具有很好参考价值的文章主要介绍了Java实现文件分片上传。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java实现文件分片上传

为什么要使用分片上传

在需要上传文件时,不可避免地会遇到上传文件内容过大,上传时间太长地问题,采用文件分片上传就可以解决这个问题。

什么是分片上传?

简单的说就是本来是需要一次搬一个很大的东西,比如是一大桶水,一次搬起来比较费事费力。我们可以把这一大桶水分装在几个或几十个或者更多的小瓶里,这样搬运起来就比较省力,也比较方便,等到目的地后,我们在将这些小瓶子里的水都倒回大桶里,这样就完成了一大桶水的搬运工作。这个将一大桶水分成许多小瓶子的过程就是分片的过程,最后将水倒回大桶的过程就是合并的过程。分片与合并也是文件分片上传的重要过程。

前后端代码

这个分片的过程是在前端实现的,上传完成后的合并工作是后端完成的。

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS分片上传-极速上传</title>
</head>
<body>
<input type="file" name="slice" id="slice" >
<br/>
</body>
<script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
    $("#slice").change(function(event) {
        var file = $("#slice")[0].files[0];
        PostFile(file,0);
    });
    //执行分片上传
    function PostFile(file,i, uuid){
        var name = file.name,                           //文件名
            size = file.size,                           //总大小
            shardSize = 10 * 1024 * 1024,                //以10MB为一个分片,每个分片的大小
            shardCount = Math.ceil(size / shardSize);   //总片数
        if(i >= shardCount){
            return;
        }
        //判断uuid是否存在
        if (uuid === null || uuid === undefined) {
            uuid = guid();
        }
        //console.log(size,i+1,shardSize);  //文件总大小,第一次,分片大小//
        var start = i * shardSize;
        var end = start + shardSize;
        var packet = file.slice(start, end);  //将文件进行切片
        /*  构建form表单进行提交  */
        var form = new FormData();
        form.append("uuid", uuid);// 前端生成uuid作为标识符传个后台每个文件都是一个uuid防止文件串了
        form.append("data", packet); //slice方法用于切出文件的一部分
        form.append("name", name);
        form.append("totalSize", size);
        form.append("total", shardCount); //总片数
        form.append("index", i + 1); //当前是第几片
        $.ajax({
            url: "http://127.0.0.1:8080/index/doPost",
            type: "POST",
            data: form,
            //timeout:"10000",  //超时10秒
            async: true, //异步
            dataType:"json",
            processData: false, //很重要,告诉jquery不要对form进行处理
            contentType: false, //很重要,指定为false才能形成正确的Content-Type
            success: function (msg) {
                console.log(msg);
                /*  表示上一块文件上传成功,继续下一次  */
                if (msg.status === 201) {
                    form = '';
                    i++;
                    PostFile(file, i, uuid);
                } else if (msg.status === 502) {
                    form = '';
                    /*  失败后,每2秒继续传一次分片文件  */
                    setInterval(function () { PostFile(file, i, uuid) }, 2000);
                } else if (msg.status === 200) {
                    merge(uuid, name)
                    console.log("上传成功");
                } else if (msg.status === 500) {
                    console.log('第'+msg.i+'次,上传文件有误!');
                } else {
                    console.log('未知错误');
                }
            }
        })
    }

    function merge(uuid, fileName) {
        $.ajax({
            url: "http://127.0.0.1:8080/index/merge",
            type: "GET",
            data: {uuid: uuid, newFileName: fileName},
            //timeout:"10000",  //超时10秒
            async: true, //异步
            dataType:"json",
            success: function (msg) {
                console.log(msg);
            }
        })
    }

    function guid() {
        return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = Math.random() * 16 | 0,
                v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }
</script>
</html>

后端代码:

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/index")
public class test_controller {
    private static final String fileUploadTempDir = "D:/portalupload/fileuploaddir";
    private static final String fileUploadDir = "D:/portalupload/file";
    @RequestMapping("/doPost")
    @ResponseBody
    public Map fragmentation(HttpServletRequest req, HttpServletResponse resp) {
        resp.addHeader("Access-Control-Allow-Origin", "*");
        Map<String, Object> map = new HashMap<>();

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) req;

        // 获得文件分片数据
        MultipartFile file = multipartRequest.getFile("data");
//        分片第几片
        int index = Integer.parseInt(multipartRequest.getParameter("index"));
//        总片数
        int total = Integer.parseInt(multipartRequest.getParameter("total"));
//        获取文件名
        String fileName = multipartRequest.getParameter("name");
        String name = fileName.substring(0, fileName.lastIndexOf("."));
        String fileEnd = fileName.substring(fileName.lastIndexOf("."));
//        前端uuid,作为标识
        String uuid = multipartRequest.getParameter("uuid");

        File uploadFile = new File(fileUploadTempDir + "/" + uuid, uuid + name + index + ".tem");

        if (!uploadFile.getParentFile().exists()) {
            uploadFile.getParentFile().mkdirs();
        }

        if (index < total) {
            try {
                file.transferTo(uploadFile);
                // 上传的文件分片名称
                map.put("status", 201);
                return map;
            } catch (IOException e) {
                e.printStackTrace();
                map.put("status", 502);
                return map;
            }
        } else {
            try {
                file.transferTo(uploadFile);
                // 上传的文件分片名称
                map.put("status", 200);
                return map;
            } catch (IOException e) {
                e.printStackTrace();
                map.put("status", 502);
                return map;
            }
        }
    }
    @RequestMapping(value = "/merge", method = RequestMethod.GET)
    @ResponseBody
    public Map merge(String uuid, String newFileName) {
        System.out.println(newFileName);
        Map retMap = new HashMap();
        try {
            File dirFile = new File(fileUploadTempDir + "/" + uuid);
            if (!dirFile.exists()) {
                throw new RuntimeException("文件不存在!");
            }
            //分片上传的文件已经位于同一个文件夹下,方便寻找和遍历(当文件数大于十的时候记得排序用冒泡排序确保顺序是正确的)
            String[] fileNames = dirFile.list();
            String name = newFileName.substring(0, newFileName.lastIndexOf("."));
            Arrays.sort(fileNames, (o1,o2)->{
                int i1 = Integer.parseInt(o1.substring(o1.indexOf(name)+name.length()).split("\\.tem")[0]);
                int i2 = Integer.parseInt(o2.substring(o2.indexOf(name)+name.length()).split("\\.tem")[0]);
                return i1 - i2;
            });

//       创建空的合并文件
            File targetFile = new File(fileUploadDir, newFileName);
            if (!targetFile.getParentFile().exists()) {
                targetFile.getParentFile().mkdirs();
            }
            RandomAccessFile writeFile = new RandomAccessFile(targetFile, "rw");

            long position = 0;
            for (String fileName : fileNames) {
                System.out.println(fileName);
                File sourceFile = new File(fileUploadTempDir + "/" + uuid, fileName);
                RandomAccessFile readFile = new RandomAccessFile(sourceFile, "rw");
                int chunksize = 1024 * 3;
                byte[] buf = new byte[chunksize];
                writeFile.seek(position);
                int byteCount;
                while ((byteCount = readFile.read(buf)) != -1) {
                    if (byteCount != chunksize) {
                        byte[] tempBytes = new byte[byteCount];
                        System.arraycopy(buf, 0, tempBytes, 0, byteCount);
                        buf = tempBytes;
                    }
                    writeFile.write(buf);
                    position = position + byteCount;
                }
                readFile.close();
                FileUtils.deleteQuietly(sourceFile);//删除缓存的临时文件
            }
            writeFile.close();
            retMap.put("code", "200");
        }catch (IOException e){
            e.printStackTrace();
            retMap.put("code", "500");
        }
        return retMap;
    }
}

测试:

Java实现文件分片上传

可以看到文件进行了分片上传,我是上传了一个系统镜像文件,4GB多,上传的也是非常的快。文章来源地址https://www.toymoban.com/news/detail-479190.html

到了这里,关于Java实现文件分片上传的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React 实现文件分片上传和下载

    文件分片上传是一种将大文件分割成多个小片段进行上传的技术。它的原理是将大文件切割成固定大小的小块,然后逐个上传这些小块,最后在服务器端将这些小块合并成完整的文件。 文件分片上传的机制可以提高上传速度和稳定性。由于大文件的上传可能会受到网络不稳定

    2024年02月13日
    浏览(27)
  • Node.js 操作百度网盘实现文件上传(小文件上传,大文件分片上传)

    Node.js 操作百度网盘实现文件上传(小文件上传,大文件分片上传) 前提准备:获取百度网盘的授权码 https://pan.baidu.com/union/doc/al0rwqzzl

    2024年02月09日
    浏览(38)
  • 基于element UI 实现大文件分片上传

    将文件进行切片,上传至服务器,上传完成后通知服务器进行合并 屏幕录制2022-11-11 16.40.06 测试用例 s-upload s-upload-img

    2024年02月01日
    浏览(29)
  • uniapp微信小程序实现大文件上传 分片上传 进度条

    一、安装   二、页面引入  三、实现功能(重要)         1.获取图片的路径         2.设置分片的大小         3.将数据放入 四、实现上传进度条 全部函数js 五、修改npm的源码,处理请求源码中请求所携带的参数问题,以及报错处理(重要) 修改npm后的源码。

    2024年02月03日
    浏览(33)
  • Minio大文件分片上传、断点续传实现

    使用minio api实现分片上传及断点续传功能。 前端准备:获取大文件的MD5值,将文件分片,5M为一分片,排好顺序,并按顺序命名(1,2,3这种后面比较好合并) 在上传分片阶段,前端有上传进度条 1、检验文件MD5值 1.1 redis中查看MD5是否存在 1.2 判断临时文件夹是否存在 boolean d

    2024年02月09日
    浏览(39)
  • 大文件分片上传的实现【前后台完整版】

    在一般的产品开发过程中,大家多少会遇到上传视频功能的需求,往往我们采用的都是对视频大小进行限制等方法,来防止上传请求超时,导致上传失败。这时候可能将视频分片上传可以对你的项目有一个小小的体验优化。 本片文章前端是vue,后台基于PHP进行的分片上传,需

    2024年02月10日
    浏览(41)
  • Springboot+WebUploader优雅实现超大文件的分片上传(一)

    在软件工程里,在处理“大”的时候一直是一个痛点和难点,如并发大、数据量大、文件大,对硬件进行升级可以解决一些问题,但这并不最聪明的办法,而对于老板来说,这也不是成本最小的办法。作为开发人员来说,在面对类似极端的问题时,只可智取,不可硬刚,最大

    2024年02月03日
    浏览(31)
  • springboot整合Minio + vue 实现文件分片上传(完整代码)

    网上关于minio分片上传的资料不太详细,缺斤少两,所以我基于他们的代码做了一些修改,demo能够正常运行起来,但是偶尔也会发生一些小bug,不过这些都无伤大雅,最终目的是理解代码背后的逻辑和流程 流程: 前端获取生成文件MD5,发送至后台判断是否有该文件缓存,有

    2024年02月02日
    浏览(41)
  • minio&前后端分离上传视频/上传大文件——前后端分离断点续传&minio分片上传实现

    🍀🍀🍀🍀分布式文件系统-minio: 第一章:分布式文件系统介绍与minio介绍与使用(附minio java client 使用) 第二章:minio前后端分离上传视频/上传大文件——前后端分离断点续传minio分片上传实现 断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包

    2024年02月03日
    浏览(39)
  • 使用Blazor WASM实现可取消的多文件带校验并发分片上传

    上传大文件时,原始HTTP文件上传功能可能会影响使用体验,此时使用分片上传功能可以有效避免原始上传的弊端。由于分片上传不是HTTP标准的一部分,所以只能自行开发相互配合的服务端和客户端。文件分片上传在许多情况时都拥有很多好处,除非已知需要上传的文件一定

    2024年02月08日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包