【问题标题】:How to traverse all files, and support pause and continue如何遍历所有文件,并支持暂停和继续
【发布时间】:2016-12-07 10:45:52
【问题描述】:

我创建了一个 NodeJS(电子)代码,用于读取特定目录和子目录中的所有文件。 我不想使用太多的高清资源,所以我在文件夹之间使用了 5ms 的延迟。

现在我的问题。我想要如果我的节点进程停止?我希望能够从它停止时继续。我该怎么做?

换句话说:如何在遍历所有文件和文件夹时保持当前状态的索引,以便我可以从停止时继续遍历。

谢谢

我的代码:

var walkAll=function(options){
    var x=0
    walk(options.dir,function(){})
    function walk(dir,callback) {
      var files=fs.readdirSync(dir);
      var stat;
      async.eachSeries(files,function(file,next){
        file=dir +'/' + file
        if (dir.match(/Recycle/)) return next() 
        if (dir.match(/.git/)) return next() 
        if (dir.match(/node_modules/)) return next() 
        fs.lstat(file,function(err,stat){
            if(err) return next()
            if(stat.mode==41398) return next()
            if (stat.isDirectory()) {
                setTimeout(function(file){
                    walk(file,next)
                }.bind(null,file),5)
            }
            else{
                x++
                if(false || x % 1000===0) console.log((new Date().valueOf()-start)/1000,x,file)
                next()
            }
        })
      },function(){
        callback()
      })
    }
}

walkAll({
    dir:'c:/',
    delay:1000
});

【问题讨论】:

  • 第一个问题是如何获得索引的持久性。借助eachSeries,可以推断出索引,它将像“循环”一样工作,因此您可以递增变量。

标签: node.js electron node-webkit


【解决方案1】:

保留要访问的子目录列表,并在每次迭代时更新列表。

以下示例中的walk 函数采用前一个状态,并返回具有下一个状态的下一个子目录的文件。

可以保存进程停止前的状态,重启时加载保存的状态继续遍历。

function walk(state, readdir) {
  let files = [], next = [];
  while (state.length > 0) {
    try {
      const current = state.shift()
      files = readdir(current).map(file => current + '/' + file)
      next = state.concat(files)
      break
    } catch(e) {}
  }
  return [next, files]
}

function main() {
  const {writeFileSync: writeFile, readdirSync: readdir} = require('fs')
  const save = './walk.json'

  let state
  try {
    state = require(save)
  } catch(e) {}
  if (!state || state.length < 1) state = ['.']

  const [nextState, files] = walk(state, readdir)
  console.log(files)
  writeFile(save, JSON.stringify(nextState, null, 2))
}

main()

【讨论】:

  • 整个问题是,如果进程重新启动,我将无法恢复 travelse
【解决方案2】:

另一种想法,

var miss = require('mississippi')
var fs = require("fs")
var through2 = require("through2")
var path = require("path")

function traverseDir(dirPath) {
  var stack = [path.resolve(dirPath)];
  var filesStack = []
  return miss.from.obj(function(size, next) {

    if (filesStack.length) {
      return next(null, filesStack.shift())
    }

    var self = this;

    try {
      while(stack.length) {
        readADir(stack.pop()).forEach(function (f) {
          if (f.t=="d") {
            stack.push(f.p)
          }
          filesStack.push(f)
        })
        if (filesStack.length) {
          return next(null, filesStack.shift())
        }
      }
      return next(null, null)
    }catch(ex) {
      return next(ex)
    }
  })
}

function readADir (dir) {
  return fs.readdirSync(dir)
    .map(function (f) {return path.join(dir, f)})
    .filter(function (f) { return !f.match(/\.git/) })
    .filter(function (f) { return !f.match(/Recycle/)})
    .filter(function (f) { return !f.match(/node_modules/)})
    .map(function (p) {
      try {
        var stat = fs.lstatSync(p);
        if(stat.mode==41398) return null
        var t = stat.isDirectory() ? "d":"f"
        return { t: t, p: p }
      }catch (ex) {}
      return null
    })
    .filter(function (o) {return o!==null})
}

function loadState(base){
  base = path.resolve(base)
  var state = {base: base, last:null}
  if (fs.existsSync("state.json")) {
    state = JSON.parse(fs.readFileSync("state.json"))
  } else {
    saveState(state)
  }
  return state
}

function saveState(state){
  fs.writeFileSync("state.json", JSON.stringify(state))
}

var state = loadState("..")
var sincePath = state.last;

var filesStream = traverseDir(state.base)
.on('end', function () {
  console.log("end")
})
.pipe(through2.obj(function (chunk, enc, next) {
  if(!sincePath) this.push(chunk)
  if(chunk.p===sincePath) {
    sincePath=null
  }
  next()
}))

var tr = through2.obj(function (chunk, enc, next) {
  state.last = chunk.p
  saveState(state)
  console.log("data %v %j", chunk.t, chunk.p)
  this.push(chunk)
  setTimeout(next, 500)
}).resume()

require('keypress')(process.stdin);
process.stdin.on('keypress', function (ch, key) {
  if(!key) return
  if (key.name == "c") {
    console.log("continue")
    filesStream.pipe(tr)
  } else if (key.name=="p") {
    console.log("pause")
    filesStream.unpipe(tr)
  }
});

console.log("Press 'c' to start")

【讨论】:

    猜你喜欢
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 2014-05-21
    相关资源
    最近更新 更多