【问题标题】:How do I move files in node.js?如何在 node.js 中移动文件?
【发布时间】:2012-01-24 15:06:28
【问题描述】:

如何在 node.js 上移动文件(如 mv 命令外壳)?有什么方法吗?或者我应该读取文件,写入新文件并删除旧文件?

【问题讨论】:

    标签: file node.js express


    【解决方案1】:

    根据 seppo0010 的评论,我使用了重命名功能来做到这一点。

    http://nodejs.org/docs/latest/api/fs.html#fs_fs_rename_oldpath_newpath_callback

    fs.rename(oldPath, newPath, callback)

    添加于:v0.0.2

    oldPath <String> | <Buffer>
    newPath <String> | <Buffer>
    callback <Function>
    

    异步重命名(2)。除了可能的例外,没有其他参数 给完成回调。

    【讨论】:

    • 对于那些想知道@seppo0010 的评论去了哪里的人:这是在我的回答中,我将其删除并作为评论发布在 OP 上。
    • 如果您跨分区或使用不支持移动文件的虚拟文件系统,这将不起作用。您最好使用 this solution 和副本后备
    【解决方案2】:

    原生使用 nodejs

    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 ")

    【讨论】:

      【解决方案3】:

      本例取自:Node.js in Action

      一个 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);
          }
      }
      

      【讨论】:

      • 工作就像一个魅力。谢谢!如果我可以添加一点:“移动”在取消链接 oldPath 时可能是一个更好的名称。
      • copy() 函数在这种情况下是可以的,但是如果有人打算将它包装在 Promise 对象中,请参阅下面我的“答案”或记住在“写入流上的“关闭”事件,而不是读取流上的事件。
      • 这看起来可以满足我的需求,但是我不知道如何使用 module.exports = function { } 样式。我是否将此代码复制到我已经拥有的应用程序中 var fs = require('fs');然后调用 fs.move(oldFile, newFile, function(err){ .... }) 而不是 fs.rename ?
      • @Curious101 你可以把它放在像 filemove.js 这样的文件中,然后像 var filemove = require('filemove');然后像 filemove(...); 一样使用它
      • 谢谢@Teomanshipahi。在这种情况下,我可以添加到 mylibrary.js 并从那里使用它。我认为这是一种众所周知的添加原型方法的方法,因此它可以在对象本身中使用。
      【解决方案4】:

      使用mv 节点模块,该模块将首先尝试执行fs.rename,然后回退到复制然后取消链接。

      【讨论】:

      • 非常适合移动文件的简单要求。
      • andrewrk 似乎是这个mv 节点模块的作者。我喜欢使用 npm 安装; npm install mv --save-dev;这是npm link
      • 这是一个开发依赖项吗?该应用程序不需要 mv 才能运行吗?
      【解决方案5】:

      util.pump 在节点 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 */ });
      

      【讨论】:

      • 这是复制/移动位于两个不同分区上的文件的正确方法。谢谢!
      【解决方案6】:

      fs-extra 模块允许您使用它的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 也会返回承诺,因此您可以使用 async/await
      • fs-extra 是一个不错的选择,因为它正确处理了需要跨设备移动文件的情况(rename 失败的情况,正如此处可能的其他答案中所警告的那样,例如 Docker 卷。)Code evidence here
      【解决方案7】:

      对高于 8.0.0 的 Node 版本使用 Promise:

      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();
      

      【讨论】:

      • 请注意,fs.rename 在带有卷的 Docker 环境中不起作用。
      • async 声明添加到moveThem 函数。
      • 你也可以只使用const { promises } = require("fs"),然后使用promises.rename(那时不需要util
      • 如果原始文件和目标文件不在同一个文件系统上,这将不起作用!
      【解决方案8】:

      使用重命名功能:

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

      在哪里

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

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

      【讨论】:

      • 请注意,如果您尝试在不同分区之间重命名文件,这将不起作用,在某些虚拟文件系统(例如 docker)上也不行
      【解决方案9】:

      这是一个使用 util.pump 的示例,来自 >> How do I move file a to a different partition or device in Node.js?

      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');
      });
      

      【讨论】:

      • 值得注意的是,您只需在跨卷移动文件时执行此操作。否则,您可以只使用fs.rename()(在卷中重命名文件和移动它是一回事)。
      • 是否可以将文件从本地机器移动到服务器?
      • 不,您需要为此使用其他东西(例如使用 FTP、HTTP 或其他协议)。
      【解决方案10】:

      正如answer above 中所述,只需我的 2 美分:copy() 方法不应该在没有轻微调整的情况下按原样用于复制文件:

      function copy(callback) {
          var readStream = fs.createReadStream(oldPath);
          var writeStream = fs.createWriteStream(newPath);
      
          readStream.on('error', callback);
          writeStream.on('error', callback);
      
          // Do not callback() upon "close" event on the readStream
          // readStream.on('close', function () {
          // Do instead upon "close" on the writeStream
          writeStream.on('close', function () {
              callback();
          });
      
          readStream.pipe(writeStream);
      }
      

      包装在 Promise 中的复制函数:

      function copy(oldPath, newPath) {
        return new Promise((resolve, reject) => {
          const readStream = fs.createReadStream(oldPath);
          const writeStream = fs.createWriteStream(newPath);
      
          readStream.on('error', err => reject(err));
          writeStream.on('error', err => reject(err));
      
          writeStream.on('close', function() {
            resolve();
          });
      
          readStream.pipe(writeStream);
        })
      

      但是,请记住,如果目标文件夹不存在,文件系统可能会崩溃。

      【讨论】:

        【解决方案11】:

        我会将所有涉及的功能(即renamecopyunlink)彼此分开,以获得灵活性并承诺一切,当然:

        const renameFile = (path, newPath) => 
          new Promise((res, rej) => {
            fs.rename(path, newPath, (err, data) =>
              err
                ? rej(err)
                : res(data));
          });
        
        const copyFile = (path, newPath, flags) =>
          new Promise((res, rej) => {
            const readStream = fs.createReadStream(path),
              writeStream = fs.createWriteStream(newPath, {flags});
        
            readStream.on("error", rej);
            writeStream.on("error", rej);
            writeStream.on("finish", res);
            readStream.pipe(writeStream);
          });
        
        const unlinkFile = path => 
          new Promise((res, rej) => {
            fs.unlink(path, (err, data) =>
              err
                ? rej(err)
                : res(data));
          });
        
        const moveFile = (path, newPath, flags) =>
          renameFile(path, newPath)
            .catch(e => {
              if (e.code !== "EXDEV")
                throw new e;
        
              else
                return copyFile(path, newPath, flags)
                  .then(() => unlinkFile(path));
            });
        

        moveFile 只是一个便利函数,我们可以单独应用这些函数,例如,当我们需要更细粒度的异常处理时。

        【讨论】:

          【解决方案12】:

          Shelljs 是一个非常方便的解决方案。

          命令: mv([options ,] 源, 目的地)

          可用选项:

          -f: 强制(默认行为)

          -n:防止覆盖

          const shell = require('shelljs');
          const status = shell.mv('README.md', '/home/my-dir');
          if(status.stderr)  console.log(status.stderr);
          else console.log('File moved!');
          

          【讨论】:

          • 你能解释一下为什么这种依赖比使用原生 Node.js API 更好吗?
          【解决方案13】:

          这是teoman shipahi's answer 的重新散列,名称稍微不那么含糊,并遵循在尝试调用它之前定义代码的设计原则。 (虽然节点允许您做其他事情,但本末倒置并不是一个好习惯。)

          function rename_or_copy_and_delete (oldPath, newPath, callback) {
          
              function copy_and_delete () {
                  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);
              }
          
              fs.rename(oldPath, newPath, 
                  function (err) {
                    if (err) {
                        if (err.code === 'EXDEV') {
                            copy_and_delete();
                        } else {
                            callback(err);
                        }
                        return;// << both cases (err/copy_and_delete)
                    }
                    callback();
                  }
              );
          }
          

          【讨论】:

            【解决方案14】:

            借助以下 URL,您可以将文件当前源复制或移动到目标源

            https://coursesweb.net/nodejs/move-copy-file

            /*********Moves the $file to $dir2 Start *********/
            var moveFile = (file, dir2)=>{
              //include the fs, path modules
              var fs = require('fs');
              var path = require('path');
            
              //gets file name and adds it to dir2
              var f = path.basename(file);
              var dest = path.resolve(dir2, f);
            
              fs.rename(file, dest, (err)=>{
                if(err) throw err;
                else console.log('Successfully moved');
              });
            };
            
            //move file1.htm from 'test/' to 'test/dir_1/'
            moveFile('./test/file1.htm', './test/dir_1/');
            /*********Moves the $file to $dir2 END *********/
            
            /*********copy the $file to $dir2 Start *********/
            var copyFile = (file, dir2)=>{
              //include the fs, path modules
              var fs = require('fs');
              var path = require('path');
            
              //gets file name and adds it to dir2
              var f = path.basename(file);
              var source = fs.createReadStream(file);
              var dest = fs.createWriteStream(path.resolve(dir2, f));
            
              source.pipe(dest);
              source.on('end', function() { console.log('Succesfully copied'); });
              source.on('error', function(err) { console.log(err); });
            };
            
            //example, copy file1.htm from 'test/dir_1/' to 'test/'
            copyFile('./test/dir_1/file1.htm', './test/');
            /*********copy the $file to $dir2 END *********/

            【讨论】:

              【解决方案15】:

              如果您尝试移动或重命名 node.js 源文件,请尝试此https://github.com/viruschidai/node-mv。它将更新所有其他文件中对该文件的引用。

              【讨论】:

                【解决方案16】:

                Node.js v10.0.0+

                const fs = require('fs')
                const { promisify } = require('util')
                const pipeline = promisify(require('stream').pipeline)
                
                await pipeline(
                  fs.createReadStream('source/file/path'),
                  fs.createWriteStream('destination/file/path')
                ).catch(err => {
                  // error handling
                })
                fs.unlink('source/file/path')
                

                【讨论】:

                  猜你喜欢
                  • 2020-12-07
                  • 2020-03-05
                  • 2012-01-09
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-11-13
                  • 2012-12-18
                  • 2021-05-14
                  相关资源
                  最近更新 更多