简体   繁体   English

循环浏览文件夹 Node.JS 中的文件

[英]Looping through files in a folder Node.JS

I am trying to loop through and pick up files in a directory, but I have some trouble implementing it.我试图循环并拾取目录中的文件,但在实现它时遇到了一些麻烦。 How to pull in multiple files and then move them to another folder?如何拉入多个文件,然后将它们移动到另一个文件夹?

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

Older answer with callbacks带有回调的旧答案

You want to use the fs.readdir function to get the directory contents and the fs.rename function to actually do the renaming.您想使用fs.readdir函数来获取目录内容,并使用fs.rename函数来实际进行重命名。 Both these functions have synchronous versions if you need to wait for them to finishing before running the code afterwards.如果您需要等待它们完成后再运行代码,这两个函数都有同步版本。

I wrote a quick script that does what you described.我写了一个快速脚本来完成你所描述的。

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

Tested on my local machine.在我的本地机器上测试。

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'.

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

Inspired by ma11hew28's answer ( shown here ), here is the same thing as above but with the async functions in fs.promises .受 ma11hew28 的回答(此处显示)的启发,这里与上面的内容相同,但在fs.promises 中使用了 async 函数。 As noted by ma11hew28, this may have memory limitations versus fs.promises.opendir added in v12.12.0.正如 ma11hew28 所指出的,与v12.12.0 中添加的 fs.promises.opendir 相比,这可能具有内存限制。

Quick code below.下面的快速代码。

//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

fs.readdir(path[, options], callback) (which Mikey A. Leonetti used in his answer ) and its variants ( fsPromises.readdir(path[, options]) and fs.readdirSync(path[, options]) ) each reads all of a directory's entries into memory at once. fs.readdir(path[, options], callback) (Mikey A. Leonetti 在他的回答中使用)及其变体( fsPromises.readdir(path[, options])fs.readdirSync(path[, options]) )一次将目录的所有条目读入内存。 That's good for most cases, but if the directory has very many entries and/or you want to lower your application's memory footprint, you could instead iterate over the directory's entries one at a time.这对大多数情况来说都很好,但是如果目录有很多条目和/或您想降低应用程序的内存占用,您可以改为一次迭代一个目录条目。

Asynchronously异步

Directories are async iterable, so you could do something like this:目录是异步可迭代的,因此您可以执行以下操作:

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)

Or, you could use dir.read() and/or dir.read(callback) directly.或者,您可以直接使用dir.read()和/或dir.read(callback)

Synchronously同步

Directories aren't sync iterable, but you could use dir.readSync() directly.目录不可同步迭代,但您可以直接使用dir.readSync() For example:例如:

const fs = require('fs')

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

Or, you could make directories sync iterable.或者,您可以使目录同步可迭代。 For example:例如:

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

And then, you could do something like this:然后,你可以做这样的事情:

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

Note: "In busy processes, use the asynchronous versions of these calls. The synchronous versions will block the entire process until they complete, halting all connections."注意:“在繁忙的进程中,使用这些调用的异步版本。同步版本将阻塞整个进程,直到它们完成,停止所有连接。”

References:参考:

Read all folders in a directory读取目录中的所有文件夹

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

The answers provided are for a single folder.提供的答案适用于单个文件夹。 Here is an asynchronous implementation for multiple folders where all the folders are processed simultaneously but the smaller folders or files gets completed first.这是多个文件夹的异步实现,其中所有文件夹同时处理,但较小的文件夹或文件首先完成。

Please comment if you have any feedback如果您有任何反馈,请发表评论

Asynchronously Multiple Folders异步多个文件夹

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM