几天来,我一直在寻找一个有效的错误解决方案
错误:EMFILE,打开的文件太多
似乎很多人都有同样的问题。通常的答案是增加文件描述符的数量。所以,我试过了:
sysctl -w kern.maxfiles=20480
缺省值为10240。在我看来,这有点奇怪,因为我在目录中处理的文件数量低于10240。更奇怪的是,在增加了文件描述符的数量之后,我仍然收到相同的错误。
第二个问题:
经过多次搜索,我找到了一个解决“打开文件太多”问题的方法:
var requestBatches = {};
function batchingReadFile(filename, callback) {
// First check to see if there is already a batch
if (requestBatches.hasOwnProperty(filename)) {
requestBatches[filename].push(callback);
return;
}
// Otherwise start a new one and make a real request
var batch = requestBatches[filename] = [callback];
FS.readFile(filename, onRealRead);
// Flush out the batch on complete
function onRealRead() {
delete requestBatches[filename];
for (var i = 0, l = batch.length; i < l; i++) {
batch[i].apply(null, arguments);
}
}
}
function printFile(file){
console.log(file);
}
dir = "/Users/xaver/Downloads/xaver/xxx/xxx/"
var files = fs.readdirSync(dir);
for (i in files){
filename = dir + files[i];
console.log(filename);
batchingReadFile(filename, printFile);
不幸的是,我仍然收到相同的错误。
这段代码有什么问题?
对于那些仍然在寻找解决方案的人来说,使用async-await对我来说很有效:
fs.readdir(<directory path></directory>, async (err, filenames) => {
if (err) {
console.log(err);
}
try {
for (let filename of filenames) {
const fileContent = await new Promise((resolve, reject) => {
fs.readFile(<dirctory path + filename>, 'utf-8', (err, content) => {
if (err) {
reject(err);
}
resolve(content);
});
});
... // do things with fileContent
}
} catch (err) {
console.log(err);
}
});
以下是我的观点:考虑到CSV文件只是几行文本,我已经流化了数据(字符串)以避免这个问题。
在我的用例中最简单的解决方案。
它可以与优雅fs或标准fs一起使用。请注意,在创建文件时,文件中不会有头文件。
// import graceful-fs or normal fs
const fs = require("graceful-fs"); // or use: const fs = require("fs")
// Create output file and set it up to receive streamed data
// Flag is to say "append" so that data can be recursively added to the same file
let fakeCSV = fs.createWriteStream("./output/document.csv", {
flags: "a",
});
和数据,需要流到文件我已经这样做了
// create custom streamer that can be invoked when needed
const customStreamer = (dataToWrite) => {
fakeCSV.write(dataToWrite + "\n");
};
注意,dataToWrite只是一个带有自定义分隔符“;”或“,”的字符串。
即。
const dataToWrite = "batman" + ";" + "superman"
customStreamer(dataToWrite);
这将向文件写入“batman;superman”。
请注意,在这个示例中没有错误捕获或其他任何东西。
文档:https://nodejs.org/api/fs.html # fs_fs_createwritestream_path_options
还有一种可能性,到目前为止,在任何答案中都没有考虑或讨论过:符号链接循环。
节点的递归文件系统监控器似乎无法检测和处理符号链接的循环。所以你可以很容易地用任意高的nfiles ulimit触发这个错误,只需运行:
mkdir a
mkdir a/b
cd a/b
ln -s .. c
GNU find会注意到符号链接循环并中止:
$ find a -follow
a
a/b
find: File system loop detected; ‘a/b/c’ is part of the same file system loop as ‘a’.
但是节点不会。如果你在树上设置了一个手表,它会抛出一个EMFILE,太多打开文件的错误。
在有包含关系的node_modules中也会发生这种情况:
parent/
package.json
child/
package.json
这也是我在做项目时遇到的问题。