Node.js过多打开文件引起错误。

4

我正在将超过220K行的数据加载到sqlite3数据库中。每一行数据都存储在一个单独的文件中,因此有超过220K个文件。

fs.readdir(dir, {}, (err, files) => {
    files.forEach(file => {

        fs.readFile(path.join(dir, file), 'utf8', (err, data) => {

            //.. process file and insert into db ..

        });
    });
});

以上情况会导致 Error: EMFILE: too many open files 错误。据我所知,我不应该关闭文件,因为显然 fs.readFile 操作的是文件并代替我关闭了它。我正在使用 Mac OS X,并且我的 ulimit 设置为 8192。

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 8192
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

我该如何解决这个错误?


1
这一切都是异步发生的,因此在某个时候,您的代码会出现问题(因为您的代码在等待其他文件关闭之前就开始永久性地打开新文件)。在这种情况下,我建议您按顺序读取文件。 - Rob
文档中提到了readFileSync。也许使用readFile更有效率,但是一次只处理少量文件。 - Arndt Jonasson
在Linux上使用prlimit命令可以显示当前计算机打开文件的限制为1024,但是它可以提高到1048576。或许您也可以这样做。但实际上同时打开如此多的文件是否是个好主意,我不确定。 - Arndt Jonasson
是的,使用 fs.readFileSync 解决了这个问题。非常感谢大家。 - punkish
请记住,使用 fs.readFileSync 只会一次打开一个文件,因为它是一个阻塞进程。 - Aramil Rey
1个回答

10

解决方案

当出现 EMFILE 错误时,您可以通过将 readFile 操作排队,并在某些内容关闭后才执行读取操作来解决此问题。幸运的是,这正是 graceful-fs 所做的,因此只需用 graceful-fs 替换 fs 模块即可解决您的问题。

const fs = require('graceful-fs');

问题

由于Node的异步性质,您的进程尝试打开超过允许数量(8192)的文件,因此会产生错误。在循环中的每次迭代开始读取一个文件,然后立即继续下一次迭代。

为了读取它们,这些文件被打开,但在读取成功或失败之前都没有关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接