Maison >Java >javaDidacticiel >Comment utiliser Java pour implémenter la fonction de reprise du point d'arrêt des fichiers ?

Comment utiliser Java pour implémenter la fonction de reprise du point d'arrêt des fichiers ?

王林
王林avant
2023-04-27 15:22:071885parcourir

Qu'est-ce que le téléchargement avec reprise

Lorsque les utilisateurs téléchargent des fichiers volumineux, cela peut prendre plusieurs heures si la connexion réseau est mauvaise. Si la ligne est interrompue, les serveurs qui ne disposent pas de téléchargements avec reprise ne peuvent retransmettre que depuis le début et les téléchargements avec reprise sont autorisés. Les utilisateurs peuvent poursuivre la transmission à partir de l'endroit où le téléchargement a été déconnecté, ce qui réduit considérablement leurs inquiétudes.

  • Résolvez le problème de la mémoire insuffisante du serveur pour le téléchargement de fichiers volumineux

  • Résolvez le problème si le téléchargement est interrompu en raison d'autres facteurs et que le téléchargement peut toujours être repris après avoir actualisé le navigateur, redémarré le navigateur (fermez le navigateur puis ouvrez-le) toujours capable de continuer le téléchargement, il peut toujours être téléchargé après le redémarrage de l'ordinateur

  • Détection de la perte de contenu du fichier en raison des fluctuations du réseau pendant le processus de téléchargement, il doit ensuite être automatiquement détecté et re-téléchargé

Solution

Front-end

  • Obligatoire Pour les fichiers téléchargés fractionnés

  • , vous devez spécifier le numéro de série du fichier fragmenté téléchargé

  • Vous devez surveiller la progression du téléchargement et contrôlez la barre de progression

  • Une fois le téléchargement terminé, vous devez envoyer une demande de fusion

Objet Blob, manipuler des fichiers

Backend

  • Interface pour télécharger des fragments

  • Interface pour fusionner des fragments

  • Interface pour obtenir des fragments

  • Autres méthodes d'outils d'assistance

Ce à quoi le front-end doit prêter attention est : la coupe de fichiers et la barre de progression

Ce que le back-end doit payer L'attention est la suivante : où les fragments sont stockés et comment fusionner les fragments

Démonstration de l'effet

Trouvez d'abord le fichier qui doit être téléchargé

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

Lorsque nous commençons le téléchargement, la barre de progression change lorsque nous cliquons pour. arrêtez le téléchargement, la barre de progression s'arrêtera.

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

Notre backend utilisera le nom du fichier + la taille du fichier MD5 pour générer les résultats du répertoire correspondant comme suit :

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

Lorsque les fichiers téléchargés sur le front-end atteignent 100. %, une demande de fusion de fichiers sera envoyée, puis tous les fragments de notre backend seront fusionnés en un seul fichier

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

Comme vous pouvez le voir sur l'image ci-dessous, tous les fragments ont disparu, alors fusionnez un fichier

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

  • Pendant le processus de téléchargement de fichiers, les fluctuations du réseau ont provoqué la perte d'une partie du flux (comparer la taille)

  • Pendant le processus de téléchargement de fichiers, le serveur a perdu des fragments (par rapport à la continuité des fragments)

  • Le fichier falsifié contenu du fichier (taille comparée)

Code principal de validation

Comment utiliser Java pour implémenter la fonction de reprise du point darrêt des fichiers ?

Code de référence

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

Parce que le Code utilise davantage de classes d'outils auto-encapsulées,Ce qui suit le code ne fournit qu'une référence pour le principe

//大文件分片上传,比如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;

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer