背景:
electron开发IM,文件图片,文件上传,不断连续上传导致崩溃。 原因是内存泄漏,不断的读取本地文件,并没有及时释放掉,一口气把用户选择的文件都读取出来,进行分片上传。
我要做什么? 重构,修改它。
需要对文件进行sha256计算,生成一个唯一hash值。
在我测试不同大小的文件生成hash的速度的时候,
发现,node原生模块crypto生成的hash值速度js-sha256生成hash速度10倍。
代码如下:
环境
创建package.json, install js-sha256
npm init -y
npm install js-sha256 --save
package.json
{
"name": "send-file-img",
"version": "1.0.0",
"description": "文件添加sha256指纹",
"main": "index.js",
"scripts": {
"start": "node index.js",
"js-sha256": "node js-sha256.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"js-sha256": "^0.9.0"
}
}
node原生模块
index.js
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
function sha256File(filePath, callback) {
const sum = crypto.createHash("sha256");
if (callback && typeof callback === "function") {
const fileStream = fs.createReadStream(filePath);
fileStream.on("error", (err) => {
return callback(err, null);
});
fileStream.on("data", (chunk) => {
try {
sum.update(chunk);
} catch (ex) {
return callback(ex, null);
}
});
fileStream.on("end", () => {
return callback(null, sum.digest("hex"));
});
} else {
sum.update(fs.readFileSync(filePath));
return sum.digest("hex");
}
}
// 获取文件信息
function getStatByFile(filePath) {
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stats) => {
if (err) {
reject(err);
return;
}
resolve(stats);
});
});
}
async function main() {
try {
const filePath = path.join("D:\\download", "./download.zip");
console.time("sha256File");
const statData = await getStatByFile(filePath);
console.log(
"statData.size :>> ",
(statData.size / (1024 * 1024)).toFixed(2),
"MB"
);
sha256File(filePath, (error, sum) => {
if (error) return console.log(error);
console.log(sum); // '345eec8796c03e90b9185e4ae3fc12c1e8ebafa540f7c7821fb5da7a54edc704'
console.timeEnd("sha256File");
});
} catch (error) {
console.error("main error", error);
}
}
main();
node index.js
PS D:\desktop\worker\send-file-img> npm start
> send-file-img@1.0.0 start
> node index.js
statData.size :>> 885.64 MB 5d930
ae8c98c7f0dade0c3bab37c23a83387aeece060ccdeeefb73055d93099201413
sha256File: 3.962s
PS D:\desktop\worker\send-file-img>
js-sha256
js-sha256.js
const path = require("path");
const fs = require("fs");
const sha256 = require("js-sha256");
main();
async function main() {
try {
console.time("read-file-total");
const filePath = path.join("D:\\download", "./download.zip");
// const filePath = path.join(__dirname, "./package.json");
// 判断 路径是否可读
fs.accessSync(path.resolve(filePath), fs.constants.R_OK);
const statData = await getStatByFile(filePath);
console.log(
"statData.size :>> ",
(statData.size / (1024 * 1024)).toFixed(2),
"MB"
);
let hash = sha256.create();
hash = await readFileBuffer(filePath, hash);
const fileHash = hash.hex();
console.log("fileHash :>> ", fileHash);
console.timeEnd("read-file-total");
} catch (error) {
console.error("main error :>> ", error);
}
}
function readFileBuffer(filePath, hash) {
return new Promise((resolve, reject) => {
try {
// can read
const readStream = fs.createReadStream(filePath);
readStream.on("data", (data) => {
hash.update(data);
});
readStream.on("end", (data) => {
resolve(hash);
});
readStream.on("error", (error) => {
reject(error);
});
} catch (error) {
reject(error);
}
});
}
// 获取文件信息
function getStatByFile(filePath) {
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stats) => {
if (err) {
reject(err);
return;
}
resolve(stats);
});
});
}
node js-sha256.js
PS D:\desktop\worker\send-file-img> npm run js-sha256
> send-file-img@1.0.0 js-sha256
> node js-sha256.js
statData.size :>> 885.64 MB
fileHash :>> ae8c98c7f0dade0c3bab37c23a83387aeece060ccdeeefb73055d93099201413
read-file-total: 47.628s
PS D:\desktop\worker\send-file-img>
完!