【发布时间】:2022-11-14 06:25:39
【问题描述】:
我有一个需要处理的大文件。该文件包含分为多个部分的标题和二进制数据。标题部分包含二进制数据部分的描述 - 定义每个部分的偏移量和长度。
我当时的想法是:
- 使用
fs.openSync()获取文件描述符 - 创建
ReadStream并读取标题部分(以获取二进制数据部分的偏移量)。流以autoClose: false打开 - 关闭“标题”
ReadStream - 创建多个
ReadStream来读取二进制数据段。每个流都有自己的start和end,每个流都以autoClose: false打开 - 处理完所有内容后关闭文件描述符
我试图测试这个概念,但在尝试打开第二个流时遇到了问题(在标题流关闭后)。错误是:
Uncaught Error Error: EBADF: bad file descriptor, read
这表明该文件不再打开以供读取(尽管所有流都是使用autoClose: false 创建的)
知道如何保持文件描述符打开直到手动关闭吗?
(async function () {
// open the file for reading
const fd = fs.openSync("c:\\some\\large\\file.txt", "r");
// initial stream that will extract the header info
const initStream = fs.createReadStream(null, {
fd,
autoClose: false,
});
// header info data
const headerContent = await extractHeaderContent(initStream);
// for test purpose
// try and extract the header again
const testSecondStream1 = fs.createReadStream(null, {
fd,
autoClose: false,
});
const testHeaderContent = await extractHeaderContent(initStream);
fs.closeSync(fd);
})();
// stream the data until the header data is retrieved
async function extractHeaderContent(initStream) {
return new Promise((resolve, reject) => {
let content = "";
initStream.on("data", (chunk) => {
if (chunk.indexOf("EndHeader") > -1) {
content += chunk.toString();
let d = content.split("EndHeader")[0] + "EndHeader";
// once the header info is extracted - close the stream
initStream.close(() => resolve(d));
}
content += chunk.toString();
});
});
}
【问题讨论】:
-
这似乎是过度优化,将一个简单的问题变成了一个复杂的问题。为什么不在每次需要新流时都打开文件?完全没有并发症。自您最近打开文件以来,有关打开文件的所有内容都将缓存在操作系统中。
-
我懂了。是的,这是过度优化的“一点”。我担心的是这些文件的大小可能只有几 GB,并且可以(不是很常见)大约 100 个数据段
-
每次阅读时使用单独的文件句柄的文件有多大并不重要。文件句柄是一个小的系统资源。按预期使用它,然后销毁流,文件句柄将被流关闭。这是解决这个问题的简单方法。我已经在我的回答中展示了复杂的方式。