Java太多打开的文件

我正在尝试写入多个文件,19确切地说。 给他们写了几百次之后,我得到了Java IOException:打开的文件过多。 但是,正如我所说,我已经打开了19个文件,并在开始时打开它们。 这里有什么问题? 我可以validation写入是否成功。

编辑:我没有使用try-catch-finally块。 我有函数抛出exception,而不是。 现在我把这个试着抓住他们,他们似乎在做的更好。

大多数人是正确的,我打开比我想象的更多的文件。 还在追踪事情 稍后我会发布更新。

重新编辑:确保所有的文件访问都被try-catch-wrapped包装,从而解决了这个问题。 谢谢

在Linux和其他类UNIX / UNIX平台上,操作系统限制了进程可能在任何给定时间打开的文件描述符的数量。 在过去,这个限制曾经是硬连线1 ,并且相对较小。 现在它大得多(数百/数千),并受到每个进程“软”的可configuration资源限制。 (查看内置的ulimitshell…)

您的Java应用程序必须超过每进程文件描述符限制。

你说你打开了19个文件,几百次之后,你会得到一个IOException,表示“文件太多了”。 现在这个特殊的exception只能在请求一个新的文件描述符时才会发生。 即当你打开一个文件(或一个pipe道或一个套接字)。 您可以通过打印IOException的堆栈跟踪来validation

除非您的应用程序正在运行一个小的资源限制(这似乎不太可能),它必须反复打开文件/套接字/pipe道,并没有closures它们。 找出发生的原因,你应该能够弄清楚该怎么做。

仅供参考,以下模式是写入文件的安全方式,保证不会泄漏文件描述符。

 Writer w = new FileWriter(...); try { // write stuff to the file } finally { try { w.close(); } catch (IOException ex) { // Log error writing file and bail out. } } 

1 – 硬编码,如编译进内核。 改变可用fd插槽的数量需要重新编译…并且可能导致其他内存不足。 在Unix通常在16位机器上运行的时代,这些事情是非常重要的。

UPDATE

Java 7的方式更简洁:

 try (Writer w = new FileWriter(...)) { // write stuff to the file } // the `w` resource is automatically closed 

更新2

显然你也可以在试图运行一个外部程序时遇到“打开太多的文件”。 基本原因如上所述。 但是,在exec(...)遇到这个问题的原因是JVM试图创build将连接到外部应用程序的标准input/输出/错误的“pipe道”文件描述符。

虽然在大多数一般情况下,错误很明显,文件句柄还没有closures,我只是在Linux上遇到了一个JDK7的实例,这个实例已经被充分的解释了。

程序打开了一个FileOutputStream(fos),一个BufferedOutputStream(bos)和一个DataOutputStream(dos)。 在写入数据输出stream后,dos被closures,我认为一切都很顺利。

在内部,dos,试图刷新bos,这个返回了Disk Full错误。 那个例外被DataOutputStream吃掉了,结果是底层的bos没有closures,所以fos仍然是打开的。

在稍后的阶段,该文件被重命名为(具有.tmp的东西)为其真名。 因此,java文件描述符跟踪器失去了原始.tmp的轨迹,但它仍然是打开的!

为了解决这个问题,我必须先自己刷新DataOutputStream,然后检索IOException并自己closuresFileOutputStream。

我希望这可以帮助别人。

在打开新文件之前,你显然没有closures你的文件描述符。 你在Windows或Linux?

对于UNIX:

正如Stephen C所build议的,将最大文件描述符值更改为更高的值可以避免这个问题。

试着看看你目前的文件描述符容量: ulimit -n

比根据您的需要改变!

希望这可以帮助。 谢谢!

最近,我有一个程序batch file,我肯定已经closures了循环中的每个文件,但错误仍然存​​在。

后来,我通过垃圾收集每百个文件急切地解决了这个问题:

 int index; while () { try { // do with outputStream... } finally { out.close(); } if (index++ % 100 = 0) System.gc(); }