gpt4 book ai didi

javascript - 在 Node.js 中比较两个大文件的最佳实践

转载 作者:行者123 更新时间:2023-12-05 01:08:23 24 4
gpt4 key购买 nike

我想比较两个大文件(5GB+),看看它们是否相同。我考虑的一种解决方案是对两者进行散列 与加密,然后比较散列。但这会花费很多时间,因为我将不得不检查整个文件,而不是在发现差异时停止。
我认为的另一个解决方案是在文件与 fs.createReadStream() 流式传输时比较文件,并在发现差异时中断。

stream.on('data', (data) => {
//compare the data from this stream with the other stream
})

但我不太确定如何让两个流同步。

最佳答案

根据您评论中的要求,如果您想了解如何编写实现来执行此操作,这里有一个。以下是它的工作原理:

  1. 打开这两个文件中的每一个
  2. 比较两个文件的大小。如果不相同,则解析为 false。
  3. 分配两个 8k 缓冲区(你可以选择使用缓冲区的大小)
  4. 将每个文件的 8k 读入缓冲区(如果文件中没有 8k,则读入更少)
  5. 比较这两个缓冲区。如果不相同,则解析为 false。
  6. 当你完成所有字节的比较后,解析为真

代码如下:

const fs = require('fs');
const fsp = fs.promises;

// resolves to true or false
async function compareFiles(fname1, fname2) {
const kReadSize = 1024 * 8;
let h1, h2;
try {
h1 = await fsp.open(fname1);
h2 = await fsp.open(fname2);
const [stat1, stat2] = await Promise.all([h1.stat(), h2.stat()]);
if (stat1.size !== stat2.size) {
return false;
}
const buf1 = Buffer.alloc(kReadSize);
const buf2 = Buffer.alloc(kReadSize);
let pos = 0;
let remainingSize = stat1.size;
while (remainingSize > 0) {
let readSize = Math.min(kReadSize, remainingSize);
let [r1, r2] = await Promise.all([h1.read(buf1, 0, readSize, pos), h2.read(buf2, 0, readSize, pos)]);
if (r1.bytesRead !== readSize || r2.bytesRead !== readSize) {
throw new Error("Failed to read desired number of bytes");
}
if (buf1.compare(buf2, 0, readSize, 0, readSize) !== 0) {
return false;
}
remainingSize -= readSize;
pos += readSize;
}
return true;
} finally {
if (h1) {
await h1.close();
}
if (h2) {
await h2.close();
}
}
}

// sample usage
compareFiles("temp.bin", "temp2.bin").then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});

这可以通过使用 Promise.allSettled() 并行打开和关闭文件来加快速度,以跟踪它们何时都打开然后都关闭,但如果一个复杂的成功打开而另一个没有,并且您不想泄漏一个打开的文件句柄,需要更多代码才能完美地做到这一点,所以我在这里保持简单。

而且,如果您真的想优化性能,则值得测试更大的缓冲区,看看它是否能让事情变得更快。

buf1.equals(buf2) 也有可能比 buf1.compare(buf2) 更快,但您必须确保读取的部分缓冲区在由于 .equals() 总是比较整个缓冲区,因此文件末尾仍然可以正常工作。您可以构建两个版本并比较它们的性能。


这是一个更复杂的版本,它可以并行打开和关闭文件,可能会稍微快一些:

const fs = require('fs');
const fsp = fs.promises;

async function compareFiles(fname1, fname2) {
const kReadSize = 1024 * 8;
let h1, h2;
try {
let openResults = await Promise.allSettled([fsp.open(fname1), fsp.open(fname2)]);
let err;
if (openResults[0].status === "fulfilled") {
h1 = openResults[0].value;
} else {
err = openResults[0].reason;
}
if (openResults[1].status === "fulfilled") {
h2 = openResults[1].value;
} else {
err = openResults[1].reason;
}
// after h1 and h2 are set (so they can be properly closed)
// throw any error we got
if (err) {
throw err;
}

const [stat1, stat2] = await Promise.all([h1.stat(), h2.stat()]);
if (stat1.size !== stat2.size) {
return false;
}
const buf1 = Buffer.alloc(kReadSize);
const buf2 = Buffer.alloc(kReadSize);
let pos = 0;
let remainingSize = stat1.size;
while (remainingSize > 0) {
let readSize = Math.min(kReadSize, remainingSize);
let [r1, r2] = await Promise.all([h1.read(buf1, 0, readSize, pos), h2.read(buf2, 0, readSize, pos)]);
if (r1.bytesRead !== readSize || r2.bytesRead !== readSize) {
throw new Error("Failed to read desired number of bytes");
}
if (buf1.compare(buf2, 0, readSize, 0, readSize) !== 0) {
return false;
}
remainingSize -= readSize;
pos += readSize;
}
return true;
} finally {
// does not return file close errors
// but does hold resolving the promise until the files are closed
// or had an error trying to close them
// Since we didn't write to the files, a close error would be fairly
// unprecedented unless the disk went down
const closePromises = [];
if (h1) {
closePromises.push(h1.close());
}
if (h2) {
closePromises.push(h2.close());
}
await Promise.allSettled(closePromises);
}
}

compareFiles("temp.bin", "temp2.bin").then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});

关于javascript - 在 Node.js 中比较两个大文件的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66114893/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com