>  기사  >  Java  >  Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

王林
王林앞으로
2023-04-27 15:22:071860검색

재개 가능한 업로드란 무엇인가요

사용자가 대용량 파일을 업로드할 때 네트워크 연결이 좋지 않으면 몇 시간이 걸릴 수 있습니다. 회선이 중단되면 재개 가능한 업로드가 없는 서버는 처음부터 다시 전송만 가능하며 재개 가능한 업로드가 허용됩니다. . 사용자는 업로드가 끊어진 곳에서 계속 전송할 수 있으므로 사용자의 걱정이 크게 줄어듭니다.

  • 대용량 파일 업로드 시 서버 메모리 부족 문제 해결

  • 다른 요인으로 인해 업로드가 종료된 경우 문제를 해결하고, 브라우저를 새로고침하고 브라우저를 다시 시작하면 업로드가 재개됩니다(닫기) 브라우저를 열고 열 수 있음) 계속 업로드할 수 있으며, 컴퓨터를 다시 시작해도 업로드할 수 있습니다

  • 업로드 프로세스 중 네트워크 변동으로 인한 파일 콘텐츠 손실을 감지한 후 자동으로 감지하여 다시 업로드해야 합니다

해결 방법

Front-end

  • 필수 분할 업로드 파일의 경우

  • , 업로드된 분할 파일의 파일 일련번호를 지정해야 합니다

  • 업로드 진행 상황을 모니터링하고 진행률 표시줄 제어

  • 업로드가 완료된 후 병합 요청을 보내야 합니다

Blob 개체, 파일 조작

Backend

  • 샤드 업로드용 인터페이스

  • 병합용 인터페이스 shards

  • 샤드 가져오기를 위한 인터페이스

  • 지원을 위한 다른 도구 방법

프론트엔드에서 주의해야 할 것은: 파일 자르기 및 진행률 표시줄

백엔드에서 주의해야 할 것

효과 시연

먼저 업로드해야 할 파일을 찾으세요

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

업로드가 시작되면 업로드 중지를 클릭하면 진행률 표시줄이 변경됩니다.

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

백엔드는 파일 이름 + 파일 크기를 MD5에 사용하여 다음과 같이 해당 디렉터리 결과를 생성합니다.

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

프런트 엔드에 업로드된 파일이 100%에 도달하면, 파일 병합 요청이 전송되면 백엔드의 모든 샤드가 하나의 파일로 병합됩니다

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

아래 그림에서 볼 수 있듯이 모든 샤드가 사라졌으므로 파일을 병합하세요

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

  • 파일 업로드 프로세스 중 네트워크 변동으로 인해 스트림 일부가 손실되었습니다(크기 비교)

  • 파일 업로드 프로세스 중에 서버에서 조각이 손실되었습니다(비교 조각 연속성)

  • 다음의 변조된 콘텐츠 파일 (비교 크기)

검증 코어 코드

Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?

참조 코드

Front-end

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <h2>html5大文件断点切割上传</h2>
    <div id="progressBar"></div>

    <input id="file" name="mov" type="file" />
    <input id="btn" type="button" value="点我上传" />
    <input id="btn1" type="button" value="点我停止上传" />

    <script type="module">
        import FileSliceUpload  from &#39;../jsutils/FileSliceUpload.js&#39;
        let testingUrl="http://localhost:7003/fileslice/testing"
        let uploadUrl="http://localhost:7003/fileslice/uploads"
        let margeUrl="http://localhost:7003/fileslice/merge-file-slice"
        let progressUrl="http://localhost:7003/fileslice/progress"
         let fileSliceUpload=  new FileSliceUpload(testingUrl,uploadUrl,margeUrl,progressUrl,"#file")
         fileSliceUpload.addProgress("#progressBar")
          let btn=  document.querySelector("#btn")
          let btn1=  document.querySelector("#btn1")
        btn.addEventListener("click",function () {
            fileSliceUpload.startUploadFile()
        })
        btn1.addEventListener("click",function () {
            fileSliceUpload.stopUploadFile()
        })

    </script>


</body>

</html>
rrree

Back-end

코드에서 자체 캡슐화된 도구 클래스를 더 많이 사용하기 때문에 다음 코드만 원리에 대한 참조를 제공합니다

//大文件分片上传,比如10G的压缩包,或者视频等,这些文件太大了  (需要后端配合进行)
class FileSliceUpload{
     
    constructor(testingUrl, uploadUrl, margeUrl,progressUrl, fileSelect) {
            this.testingUrl = testingUrl; // 检测文件上传的url
            this.uploadUrl = uploadUrl;//文件上传接口
            this.margeUrl = margeUrl; // 合并文件接口
            this.progressUrl = progressUrl; //进度接口
            this.fileSelect = fileSelect;
            this.fileObj = null;
            this.totalize = null;
            this.blockSize = 1024 * 1024; //每次上传多少字节1mb(最佳)
            this.sta = 0; //起始位置
            this.end =  this.sta +  this.blockSize; //结束位置
            this.count = 0; //分片个数
            this.barId = "bar"; //进度条id
            this.progressId = "progress";//进度数值ID
            this.fileSliceName = ""; //分片文件名称
            this.fileName = "";
            this.uploadFileInterval = null;  //上传文件定时器

    }

    /**
     *  样式可以进行修改
     * @param {*} progressId   需要将进度条添加到那个元素下面
     */
    addProgress (progressSelect) {
        let bar = document.createElement("div")
        bar.setAttribute("id", this.barId);
        let num = document.createElement("div")
        num.setAttribute("id", this.progressId);
        num.innerText = "0%"
        bar.appendChild(num);
        document.querySelector(progressSelect).appendChild(bar)
     
    }
    //续传  在上传前先去服务器检测之前是否有上传过这个文件,如果还有返回上传的的分片,那么进行续传
    // 将当前服务器上传的最后一个分片会从新上传, 避免因为网络的原因导致分片损坏 
    sequelFile () {
        if (this.fileName) {
            var xhr = new XMLHttpRequest();
            //同步
            xhr.open(&#39;GET&#39;, this.testingUrl + "/" + this.fileName+ "/" + this.blockSize+ "/" + this.totalize, false);
            xhr.send();
            if (xhr.readyState === 4 && xhr.status === 200) {
                let ret = JSON.parse(xhr.response)
                if (ret.code == 20000) {
                   let data= ret.data
                    this.count = data.code;
                    this.fileSliceName = data.fileSliceName
                    //计算起始位置和结束位置
                    this.sta = this.blockSize * this.count
                    //计算结束位置
                    this.end = this.sta + this.blockSize
                } else {
                    this.sta = 0; //从头开始
                    this.end = this.sta + this.blockSize;
                    this.count = 0; //分片个数
                }
            }
        }
    }

    stopUploadFile () {
        clearInterval(this.uploadFileInterval)
    }

    // 文件上传(单文件)
    startUploadFile () { 
         // 进度条
         let bar = document.getElementById(this.barId)
         let progressEl = document.getElementById(this.progressId)
        this.fileObj = document.querySelector(this.fileSelect).files[0];
        this.totalize = this.fileObj.size;
        this.fileName = this.fileObj.name;
 
        //查询是否存在之前上传过此文件,然后继续
        this.sequelFile()
        let ref = this; //拿到当前对象的引用,因为是在异步中使用this就是他本身而不是class
        this.uploadFileInterval = setInterval(function () {
                if (ref.sta > ref.totalize) {
                    //上传完毕后结束定时器
                    clearInterval(ref.uploadFileInterval)
                    //发送合并请求
                    ref.margeUploadFile ()
                    console.log("stop" + ref.sta);
                    return;
                };
                //分片名称
                ref.fileSliceName = ref.fileName + "-slice-" + ref.count++
                //分割文件 ,
                var blob1 =  ref.fileObj.slice(ref.sta, ref.end);
                var fd = new FormData();
                fd.append(&#39;part&#39;, blob1);
                fd.append(&#39;fileSliceName&#39;, ref.fileSliceName);
                fd.append(&#39;fileSize&#39;, ref.totalize);
                var xhr = new XMLHttpRequest();
                xhr.open(&#39;POST&#39;,  ref.uploadUrl, true);
                xhr.send(fd); //异步发送文件,不管是否成功, 会定期检测

                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        let ret = JSON.parse(xhr.response)
                        if (ret.code == 20000) {
                            //计算进度
                            let percent =  Math.ceil((ret.data*ref.blockSize/ ref.totalize) * 100)
                            if (percent > 100) {
                                percent=100
                                
                            }
                            bar.style.width = percent + &#39;%&#39;;
                            bar.style.backgroundColor = &#39;red&#39;;
                            progressEl.innerHTML = percent + &#39;%&#39;
                        }
                    }
            }


            //起始位置等于上次上传的结束位置
            ref.sta =  ref.end;
            //结束位置等于上次上传的结束位置+每次上传的字节
            ref.end = ref.sta + ref.blockSize;
        
        }, 5)

    }

    margeUploadFile () {
            console.log("检测上传的文件完整性..........");
            var xhr = new XMLHttpRequest();
            //文件分片的名称/分片大小/总大小
            xhr.open(&#39;GET&#39;, this.margeUrl+ "/" + this.fileSliceName + "/" + this.blockSize + "/" + this.totalize, true);
            xhr.send(); //发送请求
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    let ret = JSON.parse(xhr.response)
                    if (ret.code == 20000) {
                        console.log("文件上传完毕");
                    } else {
                        console.log("上传完毕但是文件上传过程中出现了异常", ret);
                    }
                }
            }
    
    }

}
export default FileSliceUpload;

위 내용은 Java를 사용하여 파일의 중단점 재개 기능을 구현하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제