到目前为止,我一直在使用Scanners 从文本文件中读取数据。例子:
File file = new File("path\\to\\file") ;
Scanner scan = new Scanner(file) ;
System.out.println(scan.nextLine()) ;
Run Code Online (Sandbox Code Playgroud)
并使用FileWriters 将数据写入文本文件。像这样:
try
{
FileWriter writer = new FileWriter("Foo.txt") ;
writer.write("hello there!") ;
writer.close()
}
catch(IOException ex)
{
ex.printStackTrace() ;
}
Run Code Online (Sandbox Code Playgroud)
几天前,我和我的导师开会。当我检查他的代码,我注意到他曾使用BufferedReader和BufferedWriter-的读取和写入文件,我以前没有使用过的方法。然后我问他使用 aBufferedReader和 aScanner从文件中读取数据有什么区别。他无法向我解释。
所以我做了一些研究,发现隐藏在引擎盖下执行这些操作的类是InputStream和OutputStream。这些类都有各自喜欢的子类FileInputStream,FileOutputStream等等。
在我的进一步研究中,我遇到了用于从文件读取数据和将数据写入文件的Reader和Writer类。同样,与InputStreamand 一样OutputStream,这些类都是abstract super类,并且有自己的子类来执行读写操作。
我对此并不感到困惑,但是......为什么?我的意思是,为什么有不同的方法来做同样的事情?有什么意义?哪种方法是处理文件输入和输出的最有效方法?
Readers 读chars; InputStreams 读bytes。(相应地,Writers写chars;OutputStreams写bytes)。
Strings 是 s 的序列char,而不是bytes。
如果要读取bytes,请使用InputStream. 如果要从文件中读取它们,请使用FileInputStream; 但并非所有bytes序列都来自文件,例如,ByteArrayInputStream允许您byte从 a 中读取s序列byte[];但是因为它是一个InputStream,所以它可以像来自文件一样以完全相同的方式使用。
如果要读取chars,请使用Reader. 如果要将 an 读InputStream作chars,请使用 an InputStreamReader,为其指定 a CharSet,这样可以将s 正确byte转换为chars。
ABufferedReader是Reader缓冲其输入的 a - 它一次从源读取多个字节,而不是一次一个。这是通常更有效的一次,而不是仅仅一个读很多,假设你将需要不止一个。它还提供了获取 aString而不是 a 的便捷方法char[]。
对我来说,BufferedReader允许你在 a 之上做的典型例子Reader是一次阅读整行。
Scanner是一个高级类,它允许您从 a String(或者,通常, a Readable,它由Readerand实现BufferedReader)读取数据,但将数据作为其他类型获取String- 例如,您可以读取1 2.0 true为int,double和boolean分别,而不必自己进行解析。
这只是建立在其他事物的功能之上,基本上是通过从Reader. Scanner 基本上是一个标记器,尽管还有更老的StringTokenizer.
Scanner老实说,这是一个很差的类:它在基本程序中经常使用(例如“输入你的名字,输入你最喜欢的颜色”);但它的锐利边缘让许多初学者望而却步(例如,扫描仪在使用 next() 或 nextFoo()? 后跳过 nextLine()?);并且执行诸如验证用户输入数字而不是一般字符串之类的事情并不像您想象的那么容易。
我发现您很快就不再使用Scanner,而只是(Buffered)Reader将所有内容都读为Strings:它只是更强大。