开发者社区> 浣熊干面包> 正文

Node.js使用fs.renameSync报cross-device link not permitted错误

简介:
+关注继续查看

在Node.js中,我们可以使用formidable模块来轻松地实现文件上传功能,代码如下:

复制代码
var Q = require('q');
var util = require('util');
var fs = require('fs');
var path = require('path');
var moment = require('moment');
var formidable = require('formidable');

var imageUpload = function (){
};

imageUpload.prototype.useFormParseCallback = function(req){
    var deferred = Q.defer();

    var form = new formidable.IncomingForm();
    form.parse(req, deferred.makeNodeResolver());
    return deferred.promise;
};

// 确保目录存在
// 如果指定的目录不存在则同步创建(多层次)
imageUpload.prototype.ensureUploadPathExist = function(uploadPath, mode){
    if (!fs.existsSync(uploadPath)){
        var pathtmp;
        uploadPath.split(path.sep).forEach(function(dirname) {
            if (pathtmp) {
                pathtmp = path.join(pathtmp, dirname);
            }
            else {
                pathtmp = dirname;
            }
            if (!fs.existsSync(pathtmp)) {
                if (!fs.mkdirSync(pathtmp, mode)) {
                    return false;
                }
            }
        });
    }

    return true;
};

imageUpload.prototype.uploadImage = function(req){
    var pathName = '/uploadImgs/';
    var uploadPath = path.join(__dirname, '../../public', pathName);

    this.ensureUploadPathExist(uploadPath);

    return this.useFormParseCallback(req).then(function(files){
        var file = files[1].imagefile;
        var fileType = file.type.split('/')[1];
        var newFileName = 'upload_' + moment().format('x') + Math.random().toString().substr(2, 10) + '.' + fileType;
        fs.renameSync(file.path, uploadPath + newFileName);
        return pathName + newFileName;
    });
};

module.exports = imageUpload;
复制代码

  上述代码中使用了模块q来处理Node.js中的回调处理,有关如何使用q可以自己上百度搜索下,这里不再赘述。函数ensureUploadPathExist()可以确保上传文件的目标目录是存在的,如果不存在它会逐级创建。文件被上传在/public/uploadImgs/目录下,并且按照指定的格式进行了重命名以防止文件被覆盖,有问题的地方在fs.renameSync()函数的调用。正常情况下如果上传的目录在本地,执行fs.renameSync()函数重命名文件是不会有问题的,但如果是跨分区重命名,例如在Linux中使用了NFS或者共享目录,则此处会报跨分区重命名的权限错误。解决办法是将fs.renameSync()函数替换为下面的代码:

复制代码
var readStream = fs.createReadStream(file.path);
var writeStream = fs.createWriteStream(uploadPath + newFileName);
 
var deferred = Q.defer();
util.pump(readStream, writeStream, deferred.makeNodeResolver());
return deferred.promise.then(function() {
    fs.unlinkSync(file.path);
    return pathName + newFileName;
});
复制代码

  使用上述代码既可以实现本地文件的上传,也可以实现跨分区的文件上传。


本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/p/5100636.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
iOS获取和监测设备基本信息——UIDevice的使用
iOS获取和监测设备基本信息——UIDevice的使用
40 0
AliOS Things 使用HAL库的USB_DEVICE MSC调用SPI W25Q128
AliOS Things的USB_DEVICE MSC的SPI W25Q128实现
897 0
Node.js使用mongodb操作MongoDB数据库
Node.js使用mongodb操作MongoDB数据库
55 0
iphone的系统信息使用[UIDevice currentDevice]
<p style="line-height:28px; margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(51,51,51); font-family:宋体; font-size:16px; border-width:0px; list-style:none"> 获取ipho
1201 0
Springboot整合Shiro的错误记录:Could not autowire. There is more than one bean of ‘Realm
今天在学习springboot整合shiro,在学习到创建安全管理器的时候出现了如下的错误,刚开始百思不得其解?
25 0
javascript:使用document.getElementById读取数据为空分析
  今天写个网页,想在页面加载onLoad时,动态显示由后台其他程序传来的数据时,用document.getElementById获取控件对象总是为空。但是检查了这个id确实是存在的。在网上查阅一番后才知道了其中的原因。
945 0
941
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载