簡體   English   中英

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 中這是一種很好的做法,但您應該控制內存消耗:

  1. 您開始使用fs.stat異步打開文件。 這意味着您的所有文件。

  2. 然后,您使用緩沖區將它們加載到內存中,但是在它們完全加載並點擊on('end',..)之前,您無法開始處理它們。 這意味着您的所有文件都在競爭完全加載到您的 RAM 中。

知道了? 你的內存使用率是 100%,你必須希望一個文件被完全加載和處理,以便為另一個文件釋放一些內存。 那就是你做錯了。

因此,您需要重新控制內存使用。 理想情況下,您應該控制一次處理多少個文件。 作為快速修復,我建議您使其與fs.statSync同步。


旁注

您的過程還涉及數據庫。 這是性能的通常嫌疑人。 您的代碼必須記錄任何數據庫錯誤。 在這里,我沒有看到潛在的死鎖或完全掃描。 所以不用擔心。 只需確保在開始插入之前創建了表格files

切勿使用for..in循環進入數組。 使用array.forEach()代替。

請使用分號; 在你的代碼中。 是的,大多數時候 JavaScript 都可以不用,但它可以避免奇怪的錯誤並減輕解釋器的工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM