NodeJS递归地对一个目录中的文件进行哈希处理

5

我能够在一个目录中实现递归文件遍历(即探索目录中的所有子目录和文件)。为此,我使用了来自Stack Overflow上一个相关帖子的回答。以下是该代码片段:

var fs = require("fs");

var tree = function(dir, done) {
  var results = {
        "path": dir,
        "children": []
      };
  fs.readdir(dir, function(err, list) {
    if (err) { return done(err); }
    var pending = list.length;
    if (!pending) { return done(null, results); }
    list.forEach(function(file) {
      fs.stat(dir + '/' + file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          tree(dir + '/' + file, function(err, res) {
            results.children.push(res);
            if (!--pending){ done(null, results); }
          });
        } else {
          results.children.push({"path": dir + "/" + file});
          if (!--pending) { done(null, results); }
        }
      });
    });
  });
};

module.exports = tree;

当我运行以下命令时:
 tree(someDirectoryPath, function(err, results) {
        if (err) throw err;

        console.log(results);
      });

我拿到了一个示例结果,就像这样:
{ path: '/Users/UserName/Desktop/1',
  children: 
   [ { path: '/Users/UserName/Desktop/1/file1' },
     { path: '/Users/UserName/Desktop/1/file2' },
     { path: '/Users/UserName/Desktop/1/file3' },
     { path: '/Users/UserName/Desktop/1/subdir1',
       children: [Object] } ] }

我还能使用fs模块的ReadStream方法来哈希特定位置的单个文件。以下是该片段:

/**
 * Checking File Integrity
 */
var fs = require('fs'),
      args = process.argv.splice('2'),
      path = require('path'),
      traverse = require('/Users/UserName/Desktop/tree.js'),
      crypto = require('crypto');
//var algorithm = ['md5', 'sha1', 'sha256', 'sha512'];
var algorithm = 'sha512';
var hashTable = new Array();

        var hash = crypto.createHash(algorithm);

        var fileStream = fs.ReadStream(args[0]);

        fileStream.on('data', function(data) {
                hash.update(data);
        fileStream.on('end', function() {
                var digest = hash.digest('hex');
                console.log('algorithm used: ', algorithm);
                console.log('hash for the file: ',digest);
                hashTable[args[0]] = digest;
                console.log(hashTable);
        });
});

args[0] 存储了 ReadStream 读取的文件位置。对于特定文件的哈希计算,控制台日志返回如下:

node fileIntegrityChecker.js hello.txt
algorithm used:  sha512
hash for the file:  9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
the hashtable is: [ 'hello.txt': '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043' ]

我的问题是,我尝试在与哈希相关的js文件中集成树模块功能。我的想法是程序将捕获用户的输入,作为目录路径,并处理该输入以遍历文件夹的所有子目录和文件。同时,应该在树模块的回调函数中包括fileStream.on方法。然而,我对回调机制并不完全了解,希望从您那里得到一些见解。
这是我尝试过的内容。
/**
 * Checking File Integrity
 */
var fs = require('fs'),
      args = process.argv.splice('2'),
      path = require('path'),
      tree = require('/Users/UserName/Desktop/tree.js'),
      crypto = require('crypto');
//var algorithm = ['md5', 'sha1', 'sha256', 'sha512'];
var algorithm = 'sha512';
var hashTable = new Array();

        var pathString = 'Users/UserName/Desktop/1';
        tree(pathString, function(err, results) {
            if (err) throw err;

            var hash = crypto.createHash(algorithm);
            var fileStream = fs.ReadStream(results.children[1]['path']);
             fileStream.on('data', function(data) {
                hash.update(data);
             fileStream.on('end', function() {
                var digest = hash.digest('hex');
                console.log('algorithm used: ', algorithm);
                console.log('hash for the file: ',digest);
                hashTable[results.children[1]['path']] = digest;
                console.log('The hashtable is: ', hashTable);
                });
            });
        });

现在,我的进展是收不到错误信息了,基本上我已经实现了我的目标。 然而,我只能显式地提取< strong >一个结果。由于某种原因,我无法想象如何迭代地(例如)获取结果JSON对象的每个子项。如果解决了这个问题,我认为问题将被完全解决。

您能否向我展示一种成功将模块和js文件组合以递归遍历目录中所有内容并为其中的每个文件创建哈希的方法。 我需要这个来最终检查文件是否发生了更改,基于它们的哈希值。谢谢!


1
回调函数看起来没问题。EISDIR 的意思是当期望的不是目录类型时,你正在尝试对目录进行操作。你追踪到哪一行抛出了这个错误了吗? - chriskelly
line tree(someDirectoryPath, function(err, results) { 出现了错误。这意味着问题可能出在我将变量 someDirectory 传递给 tree() 函数时。 - v01d
@chriskelly,我做了一些更改,请你检查一下? - v01d
请给我一些时间。我正在尝试更新我的代码。如果有什么不清楚的地方,我会告诉你的。谢谢。 - v01d
@JoshC。是的,我需要递归。不过,你能提供一个如何详细说明你可能的解决方案的示例代码吗? - v01d
显示剩余3条评论
3个回答

2
最简单的方法是在遍历目录树时生成哈希值。需要更新tree.js文件,具体操作如下:
    } else {
      var fname = dir + "/" + file};
      // put your hash generation here
      generateHash(fname, function (e, hash) {
        if (e) done(e);

        results.children.push({"path": fname, "hash" : hash);
        if (!--pending) { 
          done(null, results); 
        }
      });
    }

然后将您的哈希生成代码放在一个类似于以下的函数中:
function generateHash (filename, callback) {
    var algorithm = 'sha512';
    var hashTable = new Array();

    var hash = crypto.createHash(algorithm);
    var fileStream = fs.ReadStream(filename);

    fileStream.on('data', function(data) {
        hash.update(data);      
    });
    fileStream.on('end', function() {
        var digest = hash.digest('hex');
        callback(null, digest);
    });
}

当我尝试运行你的代码时,出现以下错误: binding.open(pathModule._makeLong(path), ^ TypeError: 路径必须是字符串。控制台抛出了 var fileStream = fs.ReadStream(filename); 这一行。 - v01d
显然我有一些内存泄漏。(node) 警告:可能检测到 EventEmitter 内存泄漏。11个结束侦听器已添加。使用 emitter.setMaxListeners() 来增加限制。 crypto.js:126 return this._handle.digest(outputEncoding); ^ 错误:未初始化 at Error (native) at Hash.digest (crypto.js:126:23) at ReadStream.<anonymous> (/Users/MacriniciDan/Desktop/tree2.js:17:31) at ReadStream.emit (events.js:129:20) at _stream_readable.js:908:16 at process._tickCallback (node.js:355:11) - v01d
1
谢谢!现在它可以工作了。感谢您的所有努力和解决方案! - v01d
回调(null,digest)行与function(e,hash)之间有趣的链接。我现在认为我更好地理解了回调。再次感谢! - v01d

1
import crypto from 'crypto';
import fs from 'fs';
import path from 'path';

// walk dir recursively
function* walkSync(dir: string) {
  const files = fs.readdirSync(dir, { withFileTypes: true });
  for (const file of files) {
    if (file.isDirectory()) {
      yield* walkSync(path.join(dir, file.name));
    } else {
      yield path.join(dir, file.name);
    }
  }
}

// concat all files hashes and hash the hashes
function dirHash(dir: string) {
  const hexes = [];
  for (const file of walkSync(dir)) {
    const buffer = fs.readFileSync(file);
    const hash = crypto.createHash('sha256');
    hash.update(buffer);
    const hex = hash.digest('hex');
    hexes.push(hex);
  }
  return crypto.createHash('sha256').update(hexes.join('')).digest('hex');
}


console.log(dirHash('./src'));

0

使用 vinyl-fs,您可以对目录进行全局匹配。这将大大减少您的代码量。

然后,您可以通过处理程序将文件传输到生成哈希值的过程中。

以下是一个示例:

fs.src(['./**/*.js'])
  .pipe(hasher)
  .pipe(concater)
  .dest('output.file')

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