在Java中:从网络路径读取时出现"打开文件太多"错误

Ser*_*erg 9 java io networking

我有下面的代码,它只是从文件夹中读取所有文件.此文件夹中有20,000个文件.该代码在本地文件夹(d:/files)上运行良好,但//robot/files在读取大约1,000 - 2,000个文件后在网络路径()上失败.

更新:文件夹是彼此的副本.

是什么导致这个问题以及如何解决它?

package cef_debug;

import java.io.*;

public class Main {

    public static void main(String[] args) throws Throwable {
        String folder = args[0];
        File[] files = (new File(folder)).listFiles();
        String line;
        for (int i = 0; i < files.length; i++) {
            BufferedReader br = new BufferedReader(new FileReader(files[i]));
            while ((line = br.readLine()) != null) {
            }
            br.close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

从网络路径(//robot/files)读取时出现以下错误:

Exception in thread "main" java.io.IOException: Too many open files
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.<init>(FileInputStream.java:106)
        at java.io.FileReader.<init>(FileReader.java:55)
        at cef_debug.Main.main(Main.java:12)
Java Result: 1
Run Code Online (Sandbox Code Playgroud)

第12行是这样的:

BufferedReader br = new BufferedReader(new FileReader(files[i]));
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 3

某些 java 版本有一个已记录的错误,并且某些文件打开次数达到了 2035 的限制。您可能刚刚达到了该限制。

来自评论:

为了澄清这个问题,在win32系统上有三种打开文件的方法:

1:使用Win32 API

2:使用MFC类框架lib。

3:使用 C-Library API(open() 和 fopen())

除了第三个选项之外,即选项1和2实际上对打开文件的数量没有限制。第三种方法被限制(出于我不知道的原因)只能打开大约。2035 个文件。这就是为什么 MS JVM 能够打开无限的(实际上)文件,但 SUN JVM 在 2035 个文件后失败(我的猜测是它使用第三种方法打开文件)。

现在,这是一个很久以前修复的老问题,但他们可能会在网络访问上使用相同的功能,而该错误可能仍然存在。

即使关闭句柄或流,Windows 也应该能够打开 >10000 个文件句柄并保持它们打开状态,如错误注释中的测试代码所示:

import java.util.*;
import java.io.*;

// if run with "java maxfiles 10000", will create 10k files in the current folder
public class maxfiles
{
    static int count = 0;
    static List files = new ArrayList();

    public static void main(String args[]) throws Exception
    {
        for (int n = 0; n < Integer.parseInt(args[0]); n++) {
            File f = new File("file" + count++);
            //save ref, so not gc'ed
            files.add(new PrintStream(new FileOutputStream(f)));
        }
        Iterator it = files.iterator();
        while (it.hasNext()) {
            PrintStream out = ( PrintStream) it.next();
            out.println("foo");
            out.flush();
        }
        System.out.println("current files open: " + files.size());
    } //~main
}
Run Code Online (Sandbox Code Playgroud)

您可以在网络共享上测试运行它,如果失败则报告错误。您也可以尝试使用不同的 JDK。至少对于OpenJDK源,除了 WinAPI 调用之外我看不到任何其他调用,所以我会尝试是否行为相同。