几天来,我一直在寻找一个有效的错误解决方案
错误: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);
不幸的是,我仍然收到相同的错误。
这段代码有什么问题?
我今天遇到了这个问题,没有找到好的解决方案,我创建了一个模块来解决它。我受到@fbartho的代码片段的启发,但希望避免覆盖fs模块。
我写的模块是Filequeue,你使用它就像fs:
var Filequeue = require('filequeue');
var fq = new Filequeue(200); // max number of files to open at once
fq.readdir('/Users/xaver/Downloads/xaver/xxx/xxx/', function(err, files) {
if(err) {
throw err;
}
files.forEach(function(file) {
fq.readFile('/Users/xaver/Downloads/xaver/xxx/xxx/' + file, function(err, data) {
// do something here
}
});
});
对于同一个问题,我做了上面提到的所有事情,但都不起作用。我试了下,它工作100%。简单的配置更改。
选项1:设置限制(大多数情况下都不起作用)
user@ubuntu:~$ ulimit -n 65535
检查电流限制
user@ubuntu:~$ ulimit -n
1024
选项2:将可用限制增加到例如65535
user@ubuntu:~$ sudo nano /etc/sysctl.conf
添加下面的行
fs.file-max = 65535
运行此命令以刷新新的配置
user@ubuntu:~$ sudo sysctl -p
编辑以下文件
user@ubuntu:~$ sudo vim /etc/security/limits.conf
向它添加以下行
root soft nproc 65535
root hard nproc 65535
root soft nofile 65535
root hard nofile 65535
编辑以下文件
user@ubuntu:~$ sudo vim /etc/pam.d/common-session
把这一行加进去
session required pam_limits.so
注销并登录并尝试以下命令
user@ubuntu:~$ ulimit -n
65535
选项3:只添加这一行
DefaultLimitNOFILE=65535
到 /etc/systemd/system.conf 和 /etc/systemd/user.conf
以下是我的观点:考虑到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
以@blak3r的回答为基础,以下是我使用的一些速记,以防它有助于其他诊断:
如果你试图调试一个正在耗尽文件描述符的node .js脚本,这里有一行给你问题节点进程使用的lsof的输出:
openFiles = child_process.execSync(`lsof -p ${process.pid}`);
这将同步运行由当前运行的Node.js进程过滤的lsof,并通过缓冲区返回结果。
然后使用console.log(openFiles.toString())将缓冲区转换为字符串并记录结果。