错误:EXDEV:不允许跨设备链接,重命名'/tmp/ on Ubuntu 16.04 LTS

12

我有上传文件的问题,使用nodejs。我已经阅读了stack1stack2。但我认为我的情况不同,在终端输出如下:

> Unhandled rejection Error: EXDEV: cross-device link not permitted,
> rename '/tmp/31941-53enly.png' ->
> 'public/files/complaint/Screenshot_2016-05-01_01-16-55.png'
>     at Error (native)
>     at Object.fs.renameSync (fs.js:681:18)
>     at null.<anonymous> (/home/faris/myprojects/orchestrale-server/routes/complaintimage.js:163:20)
>     at tryCatcher (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/util.js:16:23)
>     at Promise._settlePromiseFromHandler (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:502:31)
>     at Promise._settlePromise (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:559:18)
>     at Promise._settlePromise0 (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:604:10)
>     at Promise._settlePromises (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:683:18)
>     at Async._drainQueue (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:138:16)
>     at Async._drainQueues (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:148:10)
>     at Immediate.Async.drainQueues [as _onImmediate] (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:17:14)
>     at processImmediate [as _immediateCallback] (timers.js:383:17)

我的代码:

  if (_.isEmpty(req.files) == false) {
      var tp = avatar_folder+req.files.file.name;
      fs.renameSync(req.files.file.path, tp, function(err){});
      var avatar = req.files.file.name;
      }

这段代码在 elementary os 上可以正常运行,但是在 debian jessie 或者 Ubuntu 16 LTS 上运行时终端会报错。

有人能提供帮助吗?在 elementary os 和 arch 上这段代码执行得非常完美。


你链接的这两个问题都是由于同一个问题引起的(无法跨文件系统/分区重命名文件)。你应该尝试看看是否可以配置上传中间件,以使用与文件的最终位置相同的文件系统上的临时目录。之所以在其他发行版上可能有效的原因是,有些发行版不会为 /tmp 创建单独的分区。 - robertklep
11个回答

18

同样的问题。解决方法:读取临时文件,在新位置写入文件并删除临时文件:

        // Read the file
        fs.readFile(oldpath, function (err, data) {
            if (err) throw err;
            console.log('File read!');

            // Write the file
            fs.writeFile(newpath, data, function (err) {
                if (err) throw err;
                res.write('File uploaded and moved!');
                res.end();
                console.log('File written!');
            });

            // Delete the file
            fs.unlink(oldpath, function (err) {
                if (err) throw err;
                console.log('File deleted!');
            });
        });

非常好用。谢谢。 - moreirapontocom

6
你可以使用“mv”包来解决这个问题。 NPM链接:https://www.npmjs.com/package/mv 使用方法: 用fs.rename替换一些旧代码:
    fs.rename(temp_path, target_path, (err) => {
        if (err) {
            console.log('> FileServer.jsx | route: "/files/upload" | err:', err);
            throw err;
        }
    });

使用:

    const mv = require('mv');
    mv(temp_path, target_path, function (err) {
        if (err) {
            console.log('> FileServer.jsx | route: "/files/upload" | err:', err);
            throw err;
        }
    });

我一直在使用 fs.rename 和 Docker 卷绑定来将上传的文件从 /tmp 复制到 /app/uploads 目录。这完美地解决了问题。 - Renjith

1

请在您的链接回答中添加一些上下文! - Robert Moskal

1
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
var mv = require('mv');

http.createServer(function (req, res) {
  if (req.url == '/fileupload') {
    var form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files) {
      var oldpath = files.filetoupload.path;
     console.log(oldpath);
      var newpath = 'F:/change path to your project dir/' + files.filetoupload.name;
      mv(oldpath, newpath, function (err) {
        if (err) throw err;
        res.write('File uploaded and moved!');
        res.end();
      });
 });
  } else {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
    res.write('<input type="file" name="filetoupload"><br>');
    res.write('<input type="submit">');
    res.write('</form>');
    return res.end();
  }enter code here
}).listen(8080); 

0
在我的情况下,它在相同的磁盘路径内工作,也就是说,在c:/内,如果新路径磁盘驱动器与临时路径磁盘驱动器不同,则会出现错误。

0

当我使用docker卷时,遇到了同样的错误。

之前的解决方案对我没有用,因为我不得不编辑我使用的框架,即adminjs及其上传功能。

我想将图像存储在本地存储(图像文件夹)中,而应用程序正在docker容器中运行。

我只需在我的本地存储中创建一个名为tmp的目录,在该图像文件夹中添加TMP、TEMP、TMPDIR和TEMPDIR环境变量,并将值设置为创建的tmp文件夹。值看起来像这样:"/app/images/tmp"

我使用的docker run命令: docker run --name my-app -v /home/user/images:/app/images

希望这对其他人也有用。


0

当您的临时文件夹和Node代码位于不同的驱动器上时,就会出现此问题。

它会抛出此错误。

解决方案在另一个StackOverflow问题中。

“EXDEV:跨设备链接不允许”错误是什么意思?

来自此帖子的解决方案:

根据新的NodeJS,解决方案是不要移动,而是复制它

fs.copyFileSync(oldpath, newpath);
fs.unlink(oldpath,()=>{});

我的Windows 11安装在SSD上,而我的代码存储在HDD上。上传的图片将会下载到Windows系统盘,我正试图将其移动到HDD上。

0
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');

http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/your folder name/' + files.filetoupload.name;
fs.readFile(oldpath, function (err, data) {
if (err) throw err;
console.log('File read!');

// Write the file
fs.writeFile(newpath, data, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
console.log('File written!');
});

// Delete the file
fs.unlink(oldpath, function (err) {
if (err) throw err;
console.log('File deleted!');
});
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form- 
data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);

请考虑在您的答案中添加一些解释。这比仅仅复制粘贴正确的解决方案对原帖作者更有益处。 - ViG

0

你必须使用 fs.writeFileSync 否则 oldfile 可能会在复制之前被删除

fs.writeFileSync(newpath, data, function (err) {
    if (err) throw err;
    res.write('File uploaded and moved!');
    res.end();
    console.log('File written!');
});

// Delete the file
fs.unlink(oldpath, function (err) {
    if (err) throw err;
    console.log('File deleted!');
});

0
为了解决这个问题,你可以重写成:
fs.writeFile(path_where_to_write, file, function(err) {
    if (err) throw err; /*do something else.*/
});
/*and then Remove the file from tmp location*/
fs.unlink(tempPath);

对于多个文件,您可以根据文件数量迭代此代码块。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接