nodejs中大文件的校验和
Checksum of large files in nodejs
我正在编写一个脚本来制作我的图片的数据库。我有一个可行的脚本。它在 9 分 24 秒内浏览了一个包含 5,670 个文件、总计 13.08 GB 数据的文件夹。然后我在更新的、更大的照片上尝试它,执行似乎急剧下降。 20分钟内仅计算了一个文件夹中的三个小预览文件的哈希值,该文件夹共有431个文件,共计7.58 GB。
我做错了什么?
var fs = require('fs')
var crypto = require('crypto')
var util = require('util')
var p = require('path')
var sqlite3 = require('sqlite3').verbose()
var db = new sqlite3.Database('./sqlite.db')
const hash_algorithm = 'sha256'
var fileCount = 0
function getFiles(directory) {
fs.readdir(directory, function(err, files) {
for (var i in files) {
var filepath = directory + '/' + files[i]
fileStat(filepath)
}
})
}
function fileStat(filepath) {
fs.stat(filepath, function(err, stats) {
if (stats.isDirectory()) {
getFiles(filepath)
} else {
computeHash(filepath, hash_algorithm, function(err, hash) {
if (err) {
throw err
}
insertStat(filepath, hash, stats.size)
})
}
})
}
function computeHash(filepath, algorithm, callback) {
var hash = crypto.createHash(algorithm)
var rs = fs.createReadStream(filepath)
rs.on('open', function() {})
rs.on('error', function(err) {
throw err
})
rs.on('data', function(chunk) {
hash.update(chunk)
})
rs.on('end', function() {
hash = hash.digest('hex')
return callback(null, hash)
})
}
function getExif(filepath, callback) {
}
function insertStat(filepath, hash, size) {
var sql = "INSERT INTO files VALUES ($filename, $path, $hash, $size)"
var filename = filepath.split('/')
filename = filename[filename.length - 1]
db.run(sql, {$filename: filename, $path: filepath, $hash: hash, $size: size})
if (verbose) console.log('%s: %s', ++fileCount, filepath)
}
db.serialize(function() {
db.run('CREATE TABLE files (filename text, path text, hash text, size integer)')
})
var verbose = true
var path = process.argv[2] || '.'
path = p.resolve(path)
if (verbose) console.log('path: %s', path)
getFiles(path)
你所有的进程都是异步的。虽然在 javascript 中这是很好的做法,但您应该控制内存消耗:
您开始使用 fs.stat
异步打开文件。这意味着您的所有文件。
然后您使用缓冲区将它们加载到内存中,但是在它们完全加载并点击 on('end',..)
之前您无法开始处理它们。这意味着您的所有文件都在竞争完全加载到您的 RAM 中。
明白了吗?您的内存使用率为 100%,您必须希望一个文件已完全加载和处理,以便为另一个文件释放一些内存。那就是你做错了。
因此您需要重新控制内存使用量。理想情况下,您应该控制一次处理多少文件。作为快速修复,我建议您使其与 fs.statSync
.
同步
旁注
您的流程还涉及数据库。这是通常对性能的怀疑。您的代码必须记录任何数据库错误。在这里我看不到潜在的死锁或全面扫描。所以不用担心。只需确保在开始插入之前创建了 table files
。
切勿使用 for..in
循环进入数组。请改用 array.forEach()
。
请在您的代码中使用半列 ;
。是的,JavaScript 大部分时间都可以不用,但它会避免你出现奇怪的错误并简化解释器的工作。
我正在编写一个脚本来制作我的图片的数据库。我有一个可行的脚本。它在 9 分 24 秒内浏览了一个包含 5,670 个文件、总计 13.08 GB 数据的文件夹。然后我在更新的、更大的照片上尝试它,执行似乎急剧下降。 20分钟内仅计算了一个文件夹中的三个小预览文件的哈希值,该文件夹共有431个文件,共计7.58 GB。
我做错了什么?
var fs = require('fs')
var crypto = require('crypto')
var util = require('util')
var p = require('path')
var sqlite3 = require('sqlite3').verbose()
var db = new sqlite3.Database('./sqlite.db')
const hash_algorithm = 'sha256'
var fileCount = 0
function getFiles(directory) {
fs.readdir(directory, function(err, files) {
for (var i in files) {
var filepath = directory + '/' + files[i]
fileStat(filepath)
}
})
}
function fileStat(filepath) {
fs.stat(filepath, function(err, stats) {
if (stats.isDirectory()) {
getFiles(filepath)
} else {
computeHash(filepath, hash_algorithm, function(err, hash) {
if (err) {
throw err
}
insertStat(filepath, hash, stats.size)
})
}
})
}
function computeHash(filepath, algorithm, callback) {
var hash = crypto.createHash(algorithm)
var rs = fs.createReadStream(filepath)
rs.on('open', function() {})
rs.on('error', function(err) {
throw err
})
rs.on('data', function(chunk) {
hash.update(chunk)
})
rs.on('end', function() {
hash = hash.digest('hex')
return callback(null, hash)
})
}
function getExif(filepath, callback) {
}
function insertStat(filepath, hash, size) {
var sql = "INSERT INTO files VALUES ($filename, $path, $hash, $size)"
var filename = filepath.split('/')
filename = filename[filename.length - 1]
db.run(sql, {$filename: filename, $path: filepath, $hash: hash, $size: size})
if (verbose) console.log('%s: %s', ++fileCount, filepath)
}
db.serialize(function() {
db.run('CREATE TABLE files (filename text, path text, hash text, size integer)')
})
var verbose = true
var path = process.argv[2] || '.'
path = p.resolve(path)
if (verbose) console.log('path: %s', path)
getFiles(path)
你所有的进程都是异步的。虽然在 javascript 中这是很好的做法,但您应该控制内存消耗:
您开始使用
fs.stat
异步打开文件。这意味着您的所有文件。然后您使用缓冲区将它们加载到内存中,但是在它们完全加载并点击
on('end',..)
之前您无法开始处理它们。这意味着您的所有文件都在竞争完全加载到您的 RAM 中。
明白了吗?您的内存使用率为 100%,您必须希望一个文件已完全加载和处理,以便为另一个文件释放一些内存。那就是你做错了。
因此您需要重新控制内存使用量。理想情况下,您应该控制一次处理多少文件。作为快速修复,我建议您使其与 fs.statSync
.
旁注
您的流程还涉及数据库。这是通常对性能的怀疑。您的代码必须记录任何数据库错误。在这里我看不到潜在的死锁或全面扫描。所以不用担心。只需确保在开始插入之前创建了 table files
。
切勿使用 for..in
循环进入数组。请改用 array.forEach()
。
请在您的代码中使用半列 ;
。是的,JavaScript 大部分时间都可以不用,但它会避免你出现奇怪的错误并简化解释器的工作。