node.js分片上傳文件


前端 :

<html>

<head>
    <title>分片上傳文件</title>
</head>

<body>
    <div class="hei-bg" style="display:block;">
        <div class="user-info" style="display:block;">
            <div class="tc">請上傳大文件</div>
            <div class="user-pic picw320">
                <input id="uppic" type="file">
            </div>
            <div id="jd" class="jdb">進度</div>

            <div>
                <input type="button" value="確定" id="userbtn" class="bg-main tc userbtn">
            </div>
        </div>
    </div>
</body>
<script src="/javascripts/jquery.min.js"></script>
<script>
    $(function () {
        $('#userbtn').on('click', async function () {
            var d1 = new Date();
            let file = $("#uppic")[0].files[0], //上傳文件主體
                name = file.name, //文件名
                size = file.size, //總大小
                succeed = 0, //當前上傳數
                shardSize = 1 * 1024 * 1024, //以1MB為一個分片
                shardCount = Math.ceil(size / shardSize); //總片數

            let attr = [];
            try {
                for (let item = 0; item < shardCount; ++item) {
                    await fn(item); //同步
                    // attr.push(fn(item)); //異步
                }
                await Promise.all(attr); //異步

                $('.jdb').append(' 上傳成功');
                var d2 = new Date();
                console.log(parseInt(d2 - d1) / 1000);
            } catch (err) {
                $('.jdb').html(err);
                console.log(err);
            }

            function fn(item) {
                return new Promise((resolve, reject) => {
                    var i = item;
                    var start = i * shardSize, //當前分片開始下標
                        end = Math.min(size, start + shardSize); //結束下標

                    //構造一個表單,FormData是HTML5新增的
                    var form = new FormData();
                    form.append("data", file.slice(start, end)); //slice方法用於切出文件的一部分
                    form.append("name", name); //文件名字
                    form.append("total", shardCount); //總片數
                    form.append("index", i + 1); //當前片數
                    //Ajax提交

                    $.ajax({
                        url: "/sliceUpload",
                        type: "POST",
                        data: form,
                        timeout: 120 * 1000,
                        async: false, //同步
                        processData: false, //很重要,告訴jquery不要對form進行處理
                        contentType: false, //很重要,指定為false才能形成正確的Content-Type
                        success: function (data) {
                            ++succeed;
                            if (typeof (data) == 'string') {
                                try {
                                    data = JSON.parse(data);
                                    console.log(data.msg);
                                } catch (e) {
                                    console.log(data);
                                }
                            }
                            //生成當前進度百分比
                            var jd = `${Math.round(succeed / shardCount * 100)}%`;
                            $('.jdb').html(jd);
                            /*如果是線上,去掉定時,直接callback(),
                            這樣寫是為方便,本地測試看到進度條變化
                            因為本地做上傳測試是秒傳,沒有時間等待*/
                            setTimeout(resolve, 50);
                        }
                    });
                })
            }
        });
    });
</script>

</html>

服務器端:

async function sliceUpload(req, res) {
    var fs = require('fs');
    var multiparty = require('multiparty'); //文件上傳模塊
    var form = new multiparty.Form(); //新建表單
    //設置編輯
    form.encoding = 'utf-8';
    //設置文件存儲路徑
    form.uploadDir = "temp/"; // "Uploads/";
    //設置單文件大小限制
    // form.maxFilesSize = 200 * 1024 * 1024;
    /*form.parse表單解析函數,fields是生成數組用獲傳過參數,files是bolb文件名稱和路徑*/
    try {
        let [fields, files] = await new Promise((resolve, reject) => {
            form.parse(req, (err, fields, files) => {
                if (err) reject('test err');
                resolve([fields, files]);
            })
        })

        files = files['data'][0]; //獲取bolb文件
        var index = fields['index'][0]; //當前片數
        var total = fields['total'][0]; //總片數
        var name = fields['name'][0]; //文件名稱
        var url = 'temp/' + name + index; //臨時bolb文件新名字
        fs.renameSync(files.path, url); //修改臨時文件名字

        var pathname = 'Uploads/' + name; //上傳文件存放位置和名稱
        if (index == total) { //當最后一個分片上傳成功,進行合並
            // 檢查文件是存在,如果存在,重新設置名稱
            let NonExist = await new Promise((resolve, reject) => {
                fs.access(pathname, fs.F_OK, (err) => {
                    resolve(err);
                });
            })
            if (!NonExist) {
                var myDate = Date.now();
                pathname = 'Uploads/' + myDate + name;
            }
            logs.info('上傳文件:' + pathname);
            /*進行合並文件,先創建可寫流,再把所有BOLB文件讀出來,
                流入可寫流,生成文件
                fs.createWriteStream創建可寫流   
                aname是存放所有生成bolb文件路徑數組:
                ['Uploads/3G.rar1','Uploads/3G.rar2',...]
            */
            var writeStream = fs.createWriteStream(pathname);
            var aname = [];
            for (let i = 1; i <= total; i++) {
                let url = 'temp/' + name + i;
                let data = await new Promise(function (resolve, reject) {
                    fs.readFile(url, function (error, data) {
                        if (error) reject(error);
                        resolve(data);
                    });
                });
                //把數據寫入流里
                writeStream.write(data);
                //刪除生成臨時bolb文件              
                fs.unlink(url, () => {});
            }
            writeStream.end();
            //返回給客服端,上傳成功
            var data = JSON.stringify({
                'code': 0,
                'msg': '上傳成功'
            });
            res.send(data); //返回數據    
        } else { //還沒有上傳文件,請繼續上傳
            var data = JSON.stringify({
                'code': 1,
                'msg': '繼續上傳'
            });
            res.send(data); //返回數據    
        }
    } catch (e) {
        logs.info(e);
        res.send(e); //返回數據    
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM