如何在node.js中移动文件?

230

如何在Node.js中移动文件(类似于mv命令行)?有没有相应的方法,还是需要读取文件,同时将其写入新文件并删除旧文件?


根据您的需求,您可以使用fs模块中的cpSync函数。 - TalesMGodois
17个回答

230

6
对于那些想知道@seppo0010的评论去哪了的人:它在我的回答上,我已将其删除并作为评论发布在原始帖子上。 - Matt Ball
10
如果您正在跨越分区或使用不支持移动文件的虚拟文件系统,则此方法将不起作用。建议您使用此解决方案,其中包含备用复制功能。 - Flavien Volken

110

使用原生的Node.js

var fs = require('fs')

var oldPath = 'old/path/file.txt'
var newPath = 'new/path/file.txt'

fs.rename(oldPath, newPath, function (err) {
  if (err) throw err
  console.log('Successfully renamed - AKA moved!')
})

(注: "如果您跨越分区或使用不支持移动文件的虚拟文件系统,则此方法将无效。 [...]" – Flavien Volken 2015年9月2日12:50)


跨分区?什么意思?你是指在文件系统之间移动吗? - france1
这是一种高级的连接多个服务器的方式,或者使用像Docker这样的虚拟化平台等等。如果你不知道它,那么你不必担心,另一个用户在我的答案中添加了那个注释,尽管我认为在这种情况下没有必要。 - Hani
1
我认为他更倾向于在文件系统之间移动,而不仅仅是在Docker或网络中。这一点很重要。只说“分区”有点令人困惑。 - france1

60

这个例子摘自:Node.js实战

一个移动(move())函数,如果可能的话进行重命名,否则使用复制操作

var fs = require('fs');

module.exports = function move(oldPath, newPath, callback) {

    fs.rename(oldPath, newPath, function (err) {
        if (err) {
            if (err.code === 'EXDEV') {
                copy();
            } else {
                callback(err);
            }
            return;
        }
        callback();
    });

    function copy() {
        var readStream = fs.createReadStream(oldPath);
        var writeStream = fs.createWriteStream(newPath);

        readStream.on('error', callback);
        writeStream.on('error', callback);

        readStream.on('close', function () {
            fs.unlink(oldPath, callback);
        });

        readStream.pipe(writeStream);
    }
}

4
非常有效,谢谢!如果我可以补充一点:当unlink旧路径时,“move”可能是更好的名称。 - Jokester
copy()函数在这种情况下是可以的,但如果有人想将其包装在Promise对象中,请查看我的下面的"答案"或记住在写入流的"close"事件上解析承诺,而不是在读取流上。 - Jem
这看起来像是符合我的需求的东西,但是我不知道如何使用 module.exports = function { } 这样的风格。我应该将此代码复制到我的应用程序中,其中我已经有了 var fs = require('fs');,然后调用 fs.move(oldFile, newFile, function(err){ .... }) 而不是 fs.rename 吗? - Curious101
@Curious101 你可以将这个放在一个像 filemove.js 这样的文件中,然后像 var filemove = require('filemove'); 这样导入它,最后使用 filemove(...);。 - Teoman shipahi
谢谢@Teomanshipahi。 在这种情况下,我可以将其添加到mylibrary.js中,并从那里使用它。 我认为这是一种众所周知的方法,可以添加原型方法,使其在对象本身中可用。 - Curious101
调用unlink时,难道不应该有一个条件来判断是否出现了错误吗?(v16文档明确指出,“关闭”可能会在“错误”之后发生。)在这种情况下,您将回调(err),然后删除未成功复制的文件,然后再次回调()。(承诺只能被触发一次这一事实在这里非常方便,但是在另一个答案中的promisified代码具有相同的“删除未移动文件”模式...假设我正确地阅读了事件文档。) - xander

32

使用 mv Node.js 模块,该模块首先尝试执行 fs.rename,如果失败则会回退到复制文件并删除原文件的方式。


对于简单的文件移动需求,工作得很好。 - arcseldon
2
andrewrk似乎是这个mv节点模块的作者。我喜欢使用npm进行安装; npm install mv --save-dev; 这是npm链接 - Nate Anderson
9
这怎么成了开发依赖?难道这个应用程序不需要mv才能正常运行吗? - jgr0

19

fs-extra模块允许您使用其move()方法完成此操作。如果您想要完全将文件从一个目录移动到另一个目录(即从源文件夹中删除文件),则我已经实现了它并且它工作正常。move()方法在大多数基本情况下都可以使用。

var fs = require('fs-extra')

fs.move('/tmp/somefile', '/tmp/does/not/exist/yet/somefile', function (err) {
 if (err) return console.error(err)
 console.log("success!")
})

我相信fs-extra也会返回promises,因此您可以使用async/await。 - Anthony
1
fs-extra是一个不错的选择,因为它可以正确地处理需要在设备之间移动文件的情况(例如Docker卷等其他答案中警告的_rename_失败的情况)。代码证据在这里 - Wyck

19

util.pump 在 Node 0.10 已被弃用并生成警告消息。

 util.pump() is deprecated. Use readableStream.pipe() instead

使用流复制文件的解决方案是:

var source = fs.createReadStream('/path/to/source');
var dest = fs.createWriteStream('/path/to/dest');

source.pipe(dest);
source.on('end', function() { /* copied */ });
source.on('error', function(err) { /* error */ });

3
这是复制/移动位于两个不同分区上的文件的正确方法。谢谢! - slickplaid

17

使用Promise来处理Node版本大于8.0.0的情况:

const {promisify} = require('util');
const fs = require('fs');
const {join} = require('path');
const mv = promisify(fs.rename);

const moveThem = async () => {
  // Move file ./bar/foo.js to ./baz/qux.js
  const original = join(__dirname, 'bar/foo.js');
  const target = join(__dirname, 'baz/qux.js'); 
  await mv(original, target);
}

moveThem();

7
警告:如果您在使用 Docker 卷的环境中,使用 fs.rename 将无法正常工作。 - Atul Yadav
moveThem 函数中添加一个 async 声明。 - H_I
2
你也可以直接使用 const { promises } = require("fs"),然后使用 promises.rename(这样就不需要使用 util 了)。 - Robin Métral
如果原始文件和目标不在同一个文件系统上,则此方法无法工作! - Michael

9

使用rename函数:

fs.rename(getFileName, __dirname + '/new_folder/' + getFileName); 

where

getFilename = file.extension (old path)
__dirname + '/new_folder/' + getFileName

假设您希望保持文件名不变。

5
如果你尝试在不同分区之间重命名文件,或者在某些虚拟文件系统(例如 Docker)中重命名,这将无法正常工作。请注意。 - Flavien Volken

5

fs.rename 同样也有同步版本:

fs.renameSync(oldPath, newPath)

5

下面是一个使用util.pump的示例,来自 >> 如何在Node.js中将文件a移动到不同的分区或设备?

var fs = require('fs'),
    util = require('util');

var is = fs.createReadStream('source_file')
var os = fs.createWriteStream('destination_file');

util.pump(is, os, function() {
    fs.unlinkSync('source_file');
});

21
值得注意的是,只有在移动文件跨卷时才需要这样做。否则,您可以直接使用fs.rename()(在同一卷中重命名和移动文件是相同的操作)。 - s4y
https://dev59.com/7W455IYBdhLWcg3wD_oB#Q6OeEYcBWogLw_1bGCAG - user405398
可以将文件从本地计算机移动到服务器吗? - Hulk1991
不行,你需要使用其他东西来完成这个(比如使用FTP、HTTP或其他协议)。 - alessioalex

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