【问题标题】:Looping through files in a folder Node.JS循环浏览文件夹 Node.JS 中的文件
【发布时间】:2015-12-07 07:48:52
【问题描述】:

我正在尝试循环并获取目录中的文件,但我在实现它时遇到了一些麻烦。如何拉入多个文件,然后将它们移动到另一个文件夹?

var dirname = 'C:/FolderwithFiles';
console.log("Going to get file info!");
fs.stat(dirname, function (err, stats) {
    if (err) {
        return console.error(err);
    }
    console.log(stats);
    console.log("Got file info successfully!");

    // Check file type
    console.log("isFile ? " + stats.isFile());
    console.log("isDirectory ? " + stats.isDirectory());
});

【问题讨论】:

  • 谢谢,但我知道,。我查看了 API 并遇到了麻烦,这就是我在这里的原因

标签: javascript arrays node.js loops fs


【解决方案1】:

读取目录中的所有文件夹

  const readAllFolder = (dirMain) => {
  const readDirMain = fs.readdirSync(dirMain);

  console.log(dirMain);
  console.log(readDirMain);

  readDirMain.forEach((dirNext) => {
    console.log(dirNext, fs.lstatSync(dirMain + "/" + dirNext).isDirectory());
    if (fs.lstatSync(dirMain + "/" + dirNext).isDirectory()) {
      readAllFolder(dirMain + "/" + dirNext);
    } 
  });
};

【讨论】:

    【解决方案2】:

    提供的答案是针对单个文件夹的。这是多个文件夹的异步实现,其中所有文件夹同时处理,但较小的文件夹或文件首先完成。

    如果您有任何反馈,请发表评论

    异步多个文件夹

    const fs = require('fs')
    const util = require('util')
    const path = require('path')
    
    // Multiple folders list
    const in_dir_list = [
      'Folder 1 Large',
      'Folder 2 Small', // small folder and files will complete first
      'Folder 3 Extra Large'
    ]
    
    // BEST PRACTICES: (1) Faster folder list For loop has to be outside async_capture_callback functions for async to make sense
    //                 (2) Slower Read Write or I/O processes best be contained in an async_capture_callback functions because these processes are slower than for loop events and faster completed items get callback-ed out first 
    
    for (i = 0; i < in_dir_list.length; i++) {
      var in_dir = in_dir_list[i]
    
      // function is created (see below) so each folder is processed asynchronously for readFile_async that follows
      readdir_async_capture(in_dir, function(files_path) {
        console.log("Processing folders asynchronously ...")
    
        for (j = 0; j < files_path.length; j++) {
          file_path = files_path[j]
          file = file_path.substr(file_path.lastIndexOf("/") + 1, file_path.length)
    
          // function is created (see below) so all files are read simultaneously but the smallest file will be completed first and get callback-ed first 
          readFile_async_capture(file_path, file, function(file_string) {
            try {
              console.log(file_path)
              console.log(file_string)
            } catch (error) {
              console.log(error)
              console.log("System exiting first to catch error if not async will continue...")
              process.exit()
            }
          })
        }
      })
    }
    
    // fs.readdir async_capture function to deal with asynchronous code above
    function readdir_async_capture(in_dir, callback) {
      fs.readdir(in_dir, function(error, files) {
        if (error) { return console.log(error) }
        files_path = files.map(function(x) { return path.join(in_dir, x) })
        callback(files_path)
      })
    }
    
    // fs.readFile async_capture function to deal with asynchronous code above
    function readFile_async_capture(file_path, file, callback) {
      fs.readFile(file_path, function(error, data) {
        if (error) { return console.log(error) }
        file_string = data.toString()
        callback(file_string)
      })
    }
    
    

    【讨论】:

      【解决方案3】:

      带有回调的旧答案

      您想使用fs.readdir 函数获取目录内容并使用fs.rename 函数实际进行重命名。如果您需要在之后运行代码之前等待它们完成,这两个函数都有同步版本。

      我写了一个快速脚本,按照你的描述。

      var fs = require('fs');
      var path = require('path');
      // In newer Node.js versions where process is already global this isn't necessary.
      var process = require("process");
      
      var moveFrom = "/home/mike/dev/node/sonar/moveme";
      var moveTo = "/home/mike/dev/node/sonar/tome"
      
      // Loop through all the files in the temp directory
      fs.readdir(moveFrom, function (err, files) {
        if (err) {
          console.error("Could not list the directory.", err);
          process.exit(1);
        }
      
        files.forEach(function (file, index) {
          // Make one pass and make the file complete
          var fromPath = path.join(moveFrom, file);
          var toPath = path.join(moveTo, file);
      
          fs.stat(fromPath, function (error, stat) {
            if (error) {
              console.error("Error stating file.", error);
              return;
            }
      
            if (stat.isFile())
              console.log("'%s' is a file.", fromPath);
            else if (stat.isDirectory())
              console.log("'%s' is a directory.", fromPath);
      
            fs.rename(fromPath, toPath, function (error) {
              if (error) {
                console.error("File moving error.", error);
              } else {
                console.log("Moved file '%s' to '%s'.", fromPath, toPath);
              }
            });
          });
        });
      });
      

      在我的本地机器上测试。

      node testme.js 
      '/home/mike/dev/node/sonar/moveme/hello' is a file.
      '/home/mike/dev/node/sonar/moveme/test' is a directory.
      '/home/mike/dev/node/sonar/moveme/test2' is a directory.
      '/home/mike/dev/node/sonar/moveme/test23' is a directory.
      '/home/mike/dev/node/sonar/moveme/test234' is a directory.
      Moved file '/home/mike/dev/node/sonar/moveme/hello' to '/home/mike/dev/node/sonar/tome/hello'.
      Moved file '/home/mike/dev/node/sonar/moveme/test' to '/home/mike/dev/node/sonar/tome/test'.
      Moved file '/home/mike/dev/node/sonar/moveme/test2' to '/home/mike/dev/node/sonar/tome/test2'.
      Moved file '/home/mike/dev/node/sonar/moveme/test23' to '/home/mike/dev/node/sonar/tome/test23'.
      Moved file '/home/mike/dev/node/sonar/moveme/test234' to '/home/mike/dev/node/sonar/tome/test234'.
      

      更新:fs.promises 带有 async/await 的函数

      受 ma11hew28 的回答 (shown here) 的启发,这里与上面的内容相同,但在 fs.promises 中具有异步功能。正如 ma11hew28 所指出的,与 v12.12.0 中添加的 fs.promises.opendir 相比,这可能存在内存限制。

      下面的快速代码。

      //jshint esversion:8
      //jshint node:true
      const fs = require( 'fs' );
      const path = require( 'path' );
      
      const moveFrom = "/tmp/movefrom";
      const moveTo = "/tmp/moveto";
      
      // Make an async function that gets executed immediately
      (async ()=>{
          // Our starting point
          try {
              // Get the files as an array
              const files = await fs.promises.readdir( moveFrom );
      
              // Loop them all with the new for...of
              for( const file of files ) {
                  // Get the full paths
                  const fromPath = path.join( moveFrom, file );
                  const toPath = path.join( moveTo, file );
      
                  // Stat the file to see if we have a file or dir
                  const stat = await fs.promises.stat( fromPath );
      
                  if( stat.isFile() )
                      console.log( "'%s' is a file.", fromPath );
                  else if( stat.isDirectory() )
                      console.log( "'%s' is a directory.", fromPath );
      
                  // Now move async
                  await fs.promises.rename( fromPath, toPath );
      
                  // Log because we're crazy
                  console.log( "Moved '%s'->'%s'", fromPath, toPath );
              } // End for...of
          }
          catch( e ) {
              // Catch anything bad that happens
              console.error( "We've thrown! Whoops!", e );
          }
      
      })(); // Wrap in parenthesis and call now
      

      【讨论】:

      • 为了示例的完整性,前面存在以下行: var fs = require('fs'); var path = require('path');
      • 进程是一个全局对象。你不必要求它。否则很好,谢谢!
      • 它在以前的版本中使用过。它曾经需要被“global.process”引用,并且所需的文件会公开它。感谢您的评论。
      • 如果您需要通配符,另请参阅stackoverflow.com/a/21320251/161457
      • 我对这个解决方案唯一担心的是无法控制应用程序的流程。如果这对您的应用程序很重要 - 您可以考虑使用 promise 链。
      【解决方案4】:

      fs.readdir(path[, options], callback)(Mikey A. Leonetti 在his answer 中使用)及其变体(fsPromises.readdir(path[, options])fs.readdirSync(path[, options]))每个都一次将目录的所有条目读取到内存中。这在大多数情况下都很好,但是如果目录有很多条目和/或您想减少应用程序的内存占用,您可以一次迭代目录的条目。

      异步

      目录是异步可迭代的,所以你可以这样做:

      const fs = require('fs')
      
      async function ls(path) {
        const dir = await fs.promises.opendir(path)
        for await (const dirent of dir) {
          console.log(dirent.name)
        }
      }
      
      ls('.').catch(console.error)
      

      或者,您可以直接使用dir.read() 和/或dir.read(callback)

      同步

      目录不可同步迭代,但您可以直接使用dir.readSync()。例如:

      const fs = require('fs')
      
      const dir = fs.opendirSync('.')
      let dirent
      while ((dirent = dir.readSync()) !== null) {
        console.log(dirent.name)
      }
      dir.closeSync()
      

      或者,您可以使目录同步可迭代。例如:

      const fs = require('fs')
      
      function makeDirectoriesSyncIterable() {
        const p = fs.Dir.prototype
        if (p.hasOwnProperty(Symbol.iterator)) { return }
        const entriesSync = function* () {
          try {
            let dirent
            while ((dirent = this.readSync()) !== null) { yield dirent }
          } finally { this.closeSync() }
        }
        if (!p.hasOwnProperty(entriesSync)) { p.entriesSync = entriesSync }
        Object.defineProperty(p, Symbol.iterator, {
          configurable: true,
          enumerable: false,
          value: entriesSync,
          writable: true
        })
      }
      makeDirectoriesSyncIterable()
      

      然后,你可以这样做:

      const dir = fs.opendirSync('.')
      for (const dirent of dir) {
        console.log(dirent.name)
      }
      

      注意:“在繁忙的进程中,请使用这些调用的异步版本。同步版本将阻塞整个进程,直到它们完成,停止所有连接。”

      参考资料:

      【讨论】:

      猜你喜欢
      • 2010-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 2012-05-09
      • 1970-01-01
      相关资源
      最近更新 更多