利用formidable上传文件,并利用Date对象重命名的方法讨论
发布于 12 年前 作者 ghostfrog 10950 次浏览 最后一次编辑是 8 年前

本人新手,刚编程不久,刚学nodejs不久,请多指教。


直接入题了。日常中处理FROM的POST请求是很常见的。上传文件也是一个常见功能。编了一段代码,对上传的文件进行了储存和重命名,大家可以看看,不知道是不是一个不错的方案,还有没有错误或者值得优化的地方。另外,有没有上传相同的文件时(不管是不是同样的文件名),能不能不生成重复的文件呢?

function uploadfiles(res, req) {
console.log("Request handle 'uploadfiles' was called.");
var form = new formidable.IncomingForm();
console.log("about to parse");
form.parse(req, function(error, fields, files) {
	console.log("parsing done");
	var types = files.upload.name.split('.'); //将文件名以.分隔,取得数组最后一项作为文件后缀名。
	console.log(types);
	var date = new Date();
    var ms = Date.parse(date); //计算当前时间与1970年1月1日午夜相差的毫秒数 赋值给ms以确保文件名无重复。
    fs.renameSync(files.upload.path, "/tmp/files" + ms +"." + String(types[types.length-1]));
});	
9 回复

简单的改写了一下 没有环境 未测试。没用用过那个什么form的东西,所以上传逻辑没有做修改。重命名修改了一下。

var crypto = require('crypto');

function isValidFileName(filename) {
    var split = filename.split('.');
    if (split.length < 2) {
        return false;
    }
    return true;
}

function getExt(filename) {
    var split = filename.split('.');
    return split[split.length - 1];
}

function rand(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

function randString(size) {
    var result  = '';
    var allChar = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    
    size = size || 1;
    while (size--) {
        result += allChar.charAt(rand(0, allChar.length - 1));
    }
    
    return result;
}

function sha1(str) {
    return crypto.createHash('sha1').update(str).digest('hex');
}

function randFilename() {
    return sha1(randString(20) + new Date());
}

function uploadfiles(res, req) {
    var form = new formidable.IncomingForm();
    form.parse(req, function(error, fields, files) {
        var ext = '';
        if (isValidFileName(files.upload.name)) {
            ext = getExt(files.upload.name);
        } else {
            // 错误处理
        }
        fs.renameSync(files.upload.path, "/tmp/files" + randFilename() +"." + ext);
    }); 
}

如果不担心性能,可以对文件做md5或sha1,这样是最可以靠的。

function randFilename() {
    return sha1(randString(rand(10, 100)) + new Date());
}

突然想起,这里可以进一步随机。

修改了一下函数名。还是没有测试。

var crypto = require('crypto');

function isValidFilename(filename) {
    var split = filename.split('.');
    if (split.length < 2) {
        return false;
    }
    return true;
}

function getFilenameExt(filename) {
    var split = filename.split('.');
    return split[split.length - 1];
}

function rand(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

function randString(size) {
    var result  = '';
    var allChar = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    
    size = size || 1;
    while (size--) {
        result += allChar.charAt(rand(0, allChar.length - 1));
    }
    
    return result;
}

function sha1(str) {
    return crypto.createHash('sha1').update(str).digest('hex');
}

function randFilename() {
    return sha1(randString(rand(10, 100)) + new Date());
}

function uploadFile(res, req) {
    var form = new formidable.IncomingForm();
    
    form.parse(req, function(error, fields, files) {
        var ext = '';
        
        if (isValidFilename(files.upload.name)) {
            ext = getFilenameExt(files.upload.name);
        } else {
            // 错误处理
        }
        
        fs.renameSync(files.upload.path, "/tmp/files" + randFilename() + "." + ext);
    }); 
}

@darklowly 回复的有些晚,抱歉。非常感谢您的赐教。我测试了一下,的确是行的通的,可靠的做法。现在我在考虑如何让同样内容(可以不同名字)的文件经过算法能得到同样的代码,即减少重复文件的出现。不知道您有什么建议没?再次感谢您。

@ghostFrog 上面的回复 已经给你说过了 要对文件md5或sha1

(res,req) 好像位置反了吧?

磁盘保存的时候,文件名加上传时间到毫秒,一般就没有重复可能.

在对上传文件命名上,我也是采用时间戳,精确到毫秒还是不行的,重复的几率存在。NodeJS提供了纳秒的API,可以精确到纳秒,这样文件名是一串数字,便于排序也排除了重名的可能。

回到顶部