Scanner类是否一次将整个文件加载到内存中?

时间:2012-04-26 15:23:20

标签: java java.util.scanner

我经常使用Scanner类来读取文件,因为它非常方便。

      String inputFileName;
      Scanner fileScanner;

      inputFileName = "input.txt";
      fileScanner = new Scanner (new File(inputFileName));

我的问题是,上面的语句是否一次将整个文件加载到内存中?或者对fileScanner进行后续调用,如

      fileScanner.nextLine();

从文件中读取(即从外部存储器而不是从内存中读取)?我问,因为我担心如果文件太大而无法一次性读入内存会发生什么。谢谢。

4 个答案:

答案 0 :(得分:13)

如果你阅读了源代码,你可以自己回答这个问题。

似乎有问题的Scanner构造函数的实现显示:

public Scanner(File source) throws FileNotFoundException {
        this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
}

后者将其包含在阅读器中:

private static Readable makeReadable(ReadableByteChannel source, CharsetDecoder dec) {
    return Channels.newReader(source, dec, -1);
}

使用缓冲区大小

读取
private static final int BUFFER_SIZE = 1024; // change to 1024;

正如你在构造链的最终构造函数中看到的那样:

private Scanner(Readable source, Pattern pattern) {
        assert source != null : "source should not be null";
        assert pattern != null : "pattern should not be null";
        this.source = source;
        delimPattern = pattern;
        buf = CharBuffer.allocate(BUFFER_SIZE);
        buf.limit(0);
        matcher = delimPattern.matcher(buf);
        matcher.useTransparentBounds(true);
        matcher.useAnchoringBounds(false);
        useLocale(Locale.getDefault(Locale.Category.FORMAT));
    }

因此,扫描仪似乎不会立即读取整个文件。

答案 1 :(得分:1)

从阅读代码开始,默认情况下一次加载1 KB。对于长行文本,缓冲区的大小可以增加。 (达到你所拥有的最长文本行的大小)

答案 2 :(得分:0)

对于大型文件,最好使用BufferedReaderFileReader之类的内容。可以找到一个基本示例here

答案 3 :(得分:0)

在ACM竞赛中,快速阅读非常重要。在Java中,我们发现使用类似的东西非常快......

    FileInputStream inputStream = new FileInputStream("input.txt");
    InputStreamReader streamReader = new InputStreamReader(inputStream, "UTF-8");
    BufferedReader in = new BufferedReader(streamReader);
    Map<String, Integer> map = new HashMap<String, Integer>();
    int trees = 0;
    for (String s; (s = in.readLine()) != null; trees++) {
        Integer n = map.get(s);
        if (n != null) {
            map.put(s, n + 1);
        } else {
            map.put(s, 1);
        }
    }

该文件包含树名...

Red Alder
Ash
Aspen
Basswood
Ash
Beech
Yellow Birch
Ash
Cherry
Cottonwood

您可以使用StringTokenizer来捕捉您想要的任何部分。

如果我们对大文件使用Scanner,我们会遇到一些错误。从10000行的文件中读取100行!

  

扫描程序可以从任何实现Readable的对象中读取文本   接口。如果调用底层可读的   Readable.read(java.nio.CharBuffer)方法然后抛出IOException   扫描仪假定已到达输入的结尾。该   最近由底层可读引发的IOException可以   通过ioException()方法检索。

告诉API

祝你好运!