主要思路

每次上传文件时,根据文件的文件名判断上传文件目录是否有对应文件。
如果有文件,返回当前文件的文件长度,前端可使用进度条展示文件的上传进度。

SpringMVC

@PostMapping(value = "/fileUpload")
    public Long fileUpload(MultipartHttpServletRequest request) throws IOException {
        MultipartFile file = request.getFile("file");
        String fileName = request.getParameter("fileName");
        String position = request.getParameter("position");

        if (file != null) {
            if (!StringUtils.hasLength(position)) {
                save(fileName, file.getInputStream());
            } else {
                File targetFile = new File("E:/", fileName);
                keepGoing(file.getInputStream(), targetFile, Integer.parseInt(position));
            }
        }
        return getFileSize(fileName);
    }

根据文件名写入上传文件夹

private static void save(String fileName, InputStream inputStream) {
        // 目标文件
        File targetFile = new File("E:/", fileName);

        // 输入输出流
        FileInputStream fis = null;
        FileOutputStream fos = null;

        // 数据缓冲区
        byte[] buf = new byte[10];
        try {
            fis = (FileInputStream) inputStream;
            fos = new FileOutputStream(targetFile);
            // 数据读写
            while (fis.read(buf) != -1) {
                fos.write(buf);
                break;
            }
        } catch (FileNotFoundException e) {
            System.out.println("指定文件不存在");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭输入输出流
                if (fis != null)
                    fis.close();
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

RandomAccessFile

使用RandomAccessFile,对file文件输入流从指定位置开始写数据。

private static void keepGoing(InputStream inputStream, File target, int position) {
        RandomAccessFile writeFile = null;
        try {
            writeFile = new RandomAccessFile(target, "rw");
            writeFile.seek(position);
            // 数据缓冲区
            byte[] buf = new byte[1024];
            // 数据读写
            while (inputStream.read(buf) != -1) {
                writeFile.write(buf);
                break;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writeFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

获取文件长度

@GetMapping(value = "/getFilePosition/{fileName}")
    public Long getFilePosition(@PathVariable String fileName) {
        File targetFile = new File("E:/", fileName);
        if (!targetFile.exists()) {
            return 0L;
        }
        return targetFile.length();
    }
private static Long getFileSize(String fileName) {
        File targetFile = new File("E:/", fileName);
        return targetFile.length();
    }

前端代码

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<input type="file" multiple="multiple" name="file" id="file" onchange="init()">
<br>
<progress id="progress" max="100" value="0"></progress>
<br>
<button id="upload">上传</button>
</body>


<script type="application/javascript">
    var position = 0;

    $("#upload").click(function(){
        let file = $('#file')[0].files[0];

        const formData = new FormData();
        formData.append('file', file.slice(position, file.size));
        formData.append('fileName', getFileName())
        formData.append('position', position)

        $.ajax({
            url: '/fileUpload',
            type: 'POST',
            cache: false,    //上传文件不需要缓存
            data: formData,
            processData: false, // 告诉jQuery不要去处理发送的数据
            contentType: false, // 告诉jQuery不要去设置Content-Type请求头
            success: function (res) {
                document.getElementById('progress').max = file.size;
                document.getElementById('progress').value = res;
            },
            error: function (err) {
                console.log(err)
            }
        })
    });

    function check(){
        // 校验是否上传过文件
        // 返回上次上传位置
        $.ajaxSettings.async = false;
        $.get('/getFilePosition/' + getFileName(), function (data){
            position = data;
            document.getElementById('progress').value = data;
        })
        $.ajaxSettings.async = true;
    }


    function getFileName(){
        let originalFileName = $('#file').val();
        return originalFileName.substring(originalFileName.lastIndexOf('\\') + 1);
    }

    function init(){
        let file = $('#file')[0].files[0];
        document.getElementById('progress').max = file.size;

        check();
    }
</script>

</html>