NodeJs轻松实现文件上传详解

在NodeJS发展早期上传文件是一个较难操作的功能,随后出现了formidable。它开了一个好头,然而上传文件仍然不是那么容易。在此之后又出现了基于原文作者的教程(tutorial on handling POST requests in Express)而实现的工具connect-form。它让文件上传的过程显得简单了一些。

随着NodeJS社区的飞速发展,让上传文件这个功能变得简单得以实现肯定不会需要太长时间。现在这个功能已经得以实现—在ExpressJS中你可以很容易的上传文件。

在Express中上传文件时不再需要依赖其他的模块,文件上传可以很好工作于Express框架内。就像使用req.body一样,现在你可以使用req.files来获得你上传的文件中的具体信息。

如果你不需要指定上传文件的目录,那么你不需要对app.js做任何的改变,文件将默认上传到’/tmp’目录。但是如果你希望对你上传的文件指定特定目录,你仅仅需要修改一下内容:

app.use(express.bodyParser());

修改为 :

app.use(express.bodyParser({uploadDir:'./uploads'}));

这一配置项可以再ExpressJS的V2.5.4之后的版本中发现,具体可以参看ExpressJS的源代码,具体在express.bodyParser的第16行。在上面的示例中。文件将被上传到与express应用同级目录下的uploads目录中。

几年前,如果你需要上传任何文件或图像到服务器,那么你得完全依赖于服务器端语言如C#和PHP。在JS革命之后,一切都改变了。今天我将告诉你如何使用NodeJS上传文件到服务器,甚至不需要写一行服务器端代码。希望你会喜欢。

~~~

1.H5上传文件 #

选中文件后并显示文件信息,比如文件名,类型,尺寸
一个能够显示真实的进度条
上传的速度
剩余时间的预估
已上传的量
上传结束后服务器返回上传图片并在页面显示出来

1.1 基本界面 #

引入bootstrap

<div class="container">
    <form>
        <div class="form-group">
            <label>请选择上传的文件</label>
            <input class="form-control fileUpload" type="file" onchange="fileSelect()" name="fileUpload">
        </div>
        <div class="form-group">
            <input type="button" class="btn btn-primary" onclick="uploadFile()" value="提交">
        </div>
        <div>
            <table class="table table-bordered">
                <tr>
                    <td>文件名</td>
                    <td>文件大小</td>
                    <td>文件类型</td>
                </tr>
                <tr>
                    <td class="fileName"></td>
                    <td class="fileSize"></td>
                    <td class="fileType"></td>
                </tr>
            </table>
        </div>
    </form>
</div>

1.2 后台服务 #

var mime = require('mime');
var http = require('http');
var util = require('util');
var url = require('url');
var fs = require('fs');
var querystring = require('querystring');
var app = http.createServer(function (req,res) {
    var urlObj = url.parse(req.url,true);
    var pathname = urlObj.pathname;
    if(pathname=='/'){
        fs.createReadStream('./index.html').pipe(res);
    }else if(pathname=='/post'){
        //此处为上传使用
    }else{
        res.end('404');
    }
}).listen(8080);

1.3 选择文件显示详细信息 #

function fileSelect(){
    var file = document.querySelector('.fileUpload').files[0];
    if(file){
        var fileSize = 0;
        document.querySelector('.fileName').innerHTML = file.name;
        document.querySelector('.fileSize').innerHTML = file.size;
        document.querySelector('.fileType').innerHTML = file.type;
    }
}

1.4 formData上传 #

 function uploadFile(){
    var fd = new FormData();
    var file = document.querySelector('.fileUpload').files[0];
    fd.append('fileUpload',file);
    var xhr = new XMLHttpRequest();
    xhr.upload.addEventListener('progress',process,false); //上传监听过程
    xhr.addEventListener('load',success,false);//上传成功
    xhr.addEventListener('error',error,false);//上传出错
    xhr.addEventListener('abort',abort,false);//上传退出
    xhr.open('POST','/post');
    xhr.send(fd);
}

1.5 增加上传监听函数 #

var progress = success = error = abort = function () {};
var progress = function(event){
    var percent = Math.round(event.loaded*100/event.total);//上传的进度
    document.querySelector('.progress-bar').style.width = percent+'%';
    document.querySelector('.progress-bar')["aria-valuenow"]= percent;
}

1.6 增加进度条代码 #

<div class="progress">
    <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
    </div>
</div>

1.7 增加后台接收代码 #

var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {

});

1.8 增加单位格式化 #

function change (size){
        var fileSize = 0;
        if(size > 1024*1024){
            fileSize = Math.round(size/(1024*1024)) + 'MB';
        }else{
            fileSize = Math.round(size/(1024)) + 'kb';
        }
        return fileSize;
}

1.9 计算进度 #

var diff = event.loaded - last;
        last = event.loaded;
        //当前速度
        document.querySelector('.speed').innerHTML = change(diff);
        document.querySelector('.stage').innerHTML = change(event.loaded);
        document.querySelector('.remaining').innerHTML = ((event.total-event.loaded)/diff).toFixed(0)+'秒';

C:\Users\10354_000\AppData\Local\Temp清除缓存

1.10 接收上传数据 #

var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
    console.log(files.fileUpload);
    fs.createReadStream(files.fileUpload.path).pipe(fs.createWriteStream('./'+files.fileUpload.name));
});

2.分片上传 #

2.1 上传文件 #

function uploadFile(){
        var file = document.querySelector('.fileUpload').files[0];
        var sharedSize = 10 * 1024 * 1024;
        var sharedCount =Math.ceil(file.size/sharedSize);
        for(var i = 0; i<sharedCount;i++){
            var fd = new FormData();
            var start = i*sharedSize;
            var end = Math.min(file.size,start+sharedSize);
            fd.append('data',file.slice(start,end));
            fd.append('name','upload.psd');
            fd.append('total',sharedCount);
            fd.append('index',i+1);
            fd.append('size',sharedSize);
            var xhr = new XMLHttpRequest();
            xhr.open('POST','/post');
            xhr.send(fd);
        }
}

2.2 server修改 #

form.parse(req, function(err, fields, files) {
    var filename = fields.name;
    var index = fields.index;
    var total = fields.total;
    var size = fields.size;
    var src = fs.createReadStream(files.data.path);
    var target =fs.createWriteStream(filename+'.'+index);
    src.pipe(target);
    target.on('close', function () {
        if(successCount == total -1){
            var fd = fs.openSync(filename,'a');
            var files = fs.readdirSync('.');
            files.forEach(function (files) {
                if(files.startsWith(filename+'.')){
                    var pos = Number(path.extname(files).slice(1)-1)*size;
                    var buff = fs.readFileSync(files);
                    fs.writeSync(fd,buff,0,buff.length,pos);
                    fs.unlinkSync(files);
                }
            });
            fs.closeSync(fd);
            successCount=0;
        }else{
            successCount++;
        }
    });
    res.end('ok');
});

~

formidable简介

nodejs原生实现上传还是比较麻烦,有兴趣的自已去参考一下网上有网友写的代码

这里选择了formidable,也是github上同类功能模块人气比较高的

https://github.com/felixge/node-formidable

https://www.npmjs.org/package/formidable

优点:上传速度比较可观,占用内存也比较低,简单易用

~~~

未经允许不得转载:WEB前端开发 » NodeJs轻松实现文件上传详解

赞 (0)