扫描器与BufferedReader


283

据我所知,从Java文件中读取基于字符的数据的两种最常见的方法是使用ScannerBufferedReader。我也知道BufferedReader通过使用缓冲区来避免物理磁盘操作来有效地读取文件。

我的问题是:

  • 确实Scanner表现不如BufferedReader
  • 为什么你会选择ScannerBufferedReader反之亦然?

1
我通常也使用Scanner读取标准输入(“ Scanner in = new Scanner(System.in)”感觉更干净)。不知道这是否实际上效率较低,但是由于从std in读取会阻塞,我无法想象Scanner的效率会成为问题。
dimo414

Answers:


201

Scanner用于从流的内容中解析令牌,而BufferedReader只是读取流,并且不执行任何特殊的解析。

实际上,您可以将a传递BufferedReader给a scanner作为要解析的字符源。


55
BufferedReader是同步的,而Scanner不是同步的,因此由您决定。
Reuben

1
我知道这个主题很旧,但是当尝试从Process提供的流中吸取内容(即捕获外部命令的输出)时,使用BufferedReader的操作系统之间的结果是混合的。如单独的答案所述,一旦我将代码更改为改为使用Scanner ,一切就会开始出现一致且符合预期的情况。
2013年

@Reuben但是Scanner最终取决于输入的其他内容,这些输入很可能是同步的。
侯爵

189

在当前最新的JDK6版本/ build(b27)中,该Scanner缓冲区具有较小的缓冲区(1024个字符),而缓冲区BufferedReader8192个字符)却足够了。

至于选择,Scanner如果要解析文件,请使用,BufferedReader如果要逐行读取文件,请使用。另请参阅其先前链接的API文档的介绍性文本。

  • 解析 =将给定的输入解释为标记(部分)。它可以直接将int,string,decimal等的特定部分还给您。另请参见类中的所有这些nextXxx()方法Scanner
  • 读书 =愚蠢的流媒体。它会不断退还所有字符,而您又需要手动检查这些字符是否匹配或组成有用的内容。但是,如果您仍然不需要这样做,那么阅读就足够了。

1
好一个。感谢您的缓冲区提示。一直在寻找它,因为本地读取非常昂贵。
Achow 2012年

7
@Asif:parsing =将给定的输入解释为标记(部分)。它可以直接将特定的部分(例如int,string,decimal等)还给您。另请参见Scanner类中的所有nextXxx()方法。读书=愚蠢的流媒体。它会不断退还所有字符,而您又需要手动检查这些字符是否匹配或组成有用的内容。但是,如果您仍然不需要这样做,那么阅读就足够了。
BalusC 2015年

@BalusC好,我已经使用过readInt();readFloat(); 等等。现在有了解析的意思。而BalusC能否在聊天室中仅10分钟给我一点时间,我想问一下缓冲的原理。
Asif Mushtaq

BufferedReader在Scanner的构造函数中包装了什么?这是一个好主意吗?
vivek

1
Scanner的缓冲区将根据模式匹配的需要进行扩展。因此,如果您想要更大的缓冲区,则只需要在其上调用,例如findWithinHorizon("\\z", 8192),之后,它将使用容量为8192chars 的缓冲区(如果小于,则使用整个文件)。
霍尔格

77

看到此链接,从那里引用以下内容:

BufferedReader是一个简单的类,旨在有效地从基础流中读取。通常,由读者(如FileReader)发出的每个读取请求都会导致对基础流做出相应的读取请求。每次调用read()或readLine()都可能导致从文件中读取字节,将其转换为字符,然后返回,这可能会非常低效。如果将Reader扭曲在BufferedReader中,则效率将得到显着提高。

BufferedReader是同步的,因此可以安全地从多个线程完成对BufferedReader的读取操作。

另一方面,扫描仪内置了更多奶酪。它可以完成BufferedReader可以完成的所有工作,并且效率也相同。但是,此外,扫描程序可以使用正则表达式为基本类型和字符串解析基础流。它还可以使用您选择的定界符标记基础流。它也可以不考虑定界符而对基础流进行正向扫描!

但是,扫描仪不是线程安全的,必须从外部进行同步。

如果要编写简单的日志阅读器,则使用BufferedReader或Scanner的选择取决于正在编写的代码。但是,如果您正在编写XML解析器,则Scanner是更自然的选择。

即使在读取输入时,如果要逐行接受用户输入并说只需将其添加到文件中,则BufferedReader就足够了。另一方面,如果要接受用户输入作为具有多个选项的命令,然后打算根据指定的命令和选项执行不同的操作,则扫描仪将更适合。


“另一方面,扫描仪内置了很多奶酪;它可以完成BufferedReader可以做的所有事情,并且效率也相同。” 不同意,BufferedReader与Scanner相比要快一点,因为Scanner会解析输入数据,而BufferedReader只是读取字符序列。
Pratik

40
  1. BufferedReader具有比Scanner大得多的缓冲内存。使用BufferedReader,如果你想从一个流长字符串,使用Scanner,如果你想从流分析特定类型的标记。

  2. Scanner可以使用自定义定界符使用令牌化并将流解析为原始数据类型,而BufferedReader只能读取和存储String。

  3. BufferedReader是同步的,而Scanner不是同步的。使用BufferedReader,如果你正在使用多线程工作。

  4. Scanner隐藏IOException并BufferedReader立即抛出它。


18

我建议使用它BufferedReader来阅读文本。Scanner隐藏IOExceptionBufferedReader立即抛出。


12

BufferedReaderScanner之间的区别如下:

  1. BufferedReader已同步,但Scanner 未同步
  2. BufferedReader是线程安全的,但Scanner 不是线程安全的
  3. BufferedReader 具有较大的缓冲存储器,而Scanner 具有较小的缓冲存储器
  4. BufferedReader 速度更快,但Scanner 执行速度较慢
  5. 从控制台读取一行的代码:

    BufferedReader

     InputStreamReader isr=new InputStreamReader(System.in);
     BufferedReader br= new BufferedReader(isr);
     String st= br.readLine();

    扫描仪

    Scanner sc= new Scanner(System.in);
    String st= sc.nextLine();

8

以下是BufferedReader和Scanner之间的区别

  1. BufferedReader仅读取数据,而扫描器也解析数据。
  2. 您只能使用BufferedReader读取String,但可以使用Scanner读取int,long或float。
  3. BufferedReader在Scanner中较旧,它在jdk 1.1中存在,而JDK 5版本中添加了Scanner。
  4. BufferedReader的缓冲区大小比Scanner的1KB大(8KB)。
  5. BufferedReader更适合于读取具有长字符串的文件,而Scanner更适合于从命令提示符下读取较小的用户输入。
  6. BufferedReader是同步的,但Scanner不是同步的,这意味着您无法在多个线程之间共享Scanner。
  7. BufferedReader比Scanner更快,因为它不花时间进行解析
  8. BufferedReader比Scanner快一点
  9. 根据我们可以选择的要点,BufferedReader来自java.io包,而Scanner来自java.util包。

谢谢


6

主要区别:

  1. 扫描器

  • 一个简单的文本扫描器,可以使用正则表达式解析原始类型和字符串。
  • 扫描程序使用定界符模式将其输入分成令牌,默认情况下,该模式与空格匹配。然后,可以使用各种下一种方法将生成的令牌转换为不同类型的值。

 String input = "1 fish 2 fish red fish blue fish";
 Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
 System.out.println(s.nextInt());
 System.out.println(s.nextInt());
 System.out.println(s.next());
 System.out.println(s.next());
 s.close(); 

打印以下输出:

 1
 2
 red
 blue 

可以使用以下代码生成相同的输出,该代码使用正则表达式一次解析所有四个标记:

 String input = "1 fish 2 fish red fish blue fish";

 Scanner s = new Scanner(input);
 s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
 MatchResult result = s.match();
 for (int i=1; i<=result.groupCount(); i++)
     System.out.println(result.group(i));
 s.close(); `


  1. BufferedReader:

    • 从字符输入流中读取文本,缓冲字符,以便有效读取字符,数组和行。

    • 可以指定缓冲区大小,也可以使用默认大小。对于大多数用途,默认值足够大。

通常,由读取器发出的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。因此,建议将BufferedReader包裹在其read()操作可能会很昂贵的任何Reader上,例如FileReaders和InputStreamReaders。例如,

BufferedReader in
   = new BufferedReader(new FileReader("foo.in"));

将缓冲来自指定文件的输入。如果不进行缓冲,则每次调用read()或readLine()都会导致从文件中读取字节,将其转换为字符,然后返回,这可能会非常低效。通过将每个DataInputStream替换为适当的BufferedReader,可以本地化使用DataInputStreams进行文本输入的程序。

资料来源:链接


3

有多种不同的方法可以在Java中进行输入,例如:

1)BufferedReader 2)扫描仪3)命令行参数

BufferedReader从字符输入流中读取文本,缓冲字符,以便有效读取字符,数组和行。

其中Scanner是一个简单的文本扫描程序,可以使用正则表达式解析原始类型和字符串。

如果您正在编写一个简单的日志读取器,那么带缓冲读取器就足够了。如果您正在编写XML解析器,则Scanner是更自然的选择。

有关更多信息,请参阅:

http://java.meritcampus.com/t/240/Bufferedreader?tc=mm69


1

下面的答案来自 “从控制台读取”:JAVA Scanner与BufferedReader

从控制台读取输入时,有两个选项可以实现该目的。首先使用Scanner,另一个使用BufferedReader。他们两个都有不同的特征。这意味着如何使用它。

扫描程序将给定的输入视为令牌。BufferedReader只是逐行读取给定输入的字符串。它自己扫描程序提供解析功能,就像nextInt(),nextFloat()一样。

但是,其他之间有什么区别?

  • 扫描程序将给定的输入视为令牌。BufferedReader作为流线/字符串
  • 扫描程序使用正则表达式标记给定的输入。使用BufferedReader必须编写额外的代码
  • BufferedReader比Scanner *点号更快。2
  • 扫描仪未同步,BufferedReader已同步

从JDK 1.5版开始,扫描仪自带。

什么时候应该使用扫描仪或缓冲读取器?

查看它们之间的主要区别,一个使用标记化,另一个使用流线。当您需要解析功能时,请改用Scanner。但是,我对BufferedReader更满意。当您需要读取文件时,请使用BufferedReader,因为它在读取文件时使用缓冲区。或者,您可以将BufferedReader用作Scanner的输入。


0
  1. BufferedReader可能会为您提供更好的性能(因为Scanner基于InputStreamReader,请查看源代码)。ups,它使用nio读取文件。当我针对大文件的BufferedReader性能测试了nio性能时,nio显示了更好的性能。
  2. 要读取文件,请尝试使用Apache Commons IO。

0

我更喜欢,Scanner因为它不会引发检查异常,因此它的使用导致代码更加简化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.