似乎有很多方法可以用Java读取文本文件(BufferedReader
,DataInputStream
等。)我个人最喜欢的是Scanner
,其中File
为构造函数(它只是更简单,更好地处理mathy数据处理,并且具有熟悉的语法)。
鲍里斯蜘蛛也提到Channel
和RandomAccessFile
。
有人可以解释每种方法的优缺点吗?具体来说,我什么时候才想使用它们?
(编辑)我想我应该具体一点,并补充说我对Scanner
方法有强烈的偏好。所以真正的问题是,当不我想使用它时?
答案 0 :(得分:14)
让我们从头开始。问题是你想做什么?
了解文件的实际内容非常重要。文件是光盘上的字节集合,这些字节是您的数据。 Java提供了多种抽象级别:
File(Input|Output)Stream
- 将这些字节读作byte
。File(Reader|Writer)
- 从一个字节流中读取char
。Scanner
- 从char
流中读取并标记它。RandomAccessFile
- 将这些字节读取为可搜索的byte[]
。FileChannel
- 以安全的多线程方式读取这些字节。除此之外还有Decorators,例如,您可以使用BufferedXXX
添加缓冲。您可以使用FileWriter
向PrintWriter
添加换行感知功能。您可以使用InputStream
将Reader
转换为InputStreamReader
(目前是指定Reader
的字符编码的唯一方法。)
所以 - 什么时候我不想使用它[a Scanner
]?。
如果你愿意,你不会使用Scanner
,(这些是一些例子):
byte
s byte
从一个文件复制到另一个文件,可能需要进行一些过滤。 Scanner(File file)
构造函数使用File
并使用平台默认编码打开FileInputStream
也没有任何价值 - 这几乎总是<强烈的>糟糕的想法。通常认为您应该明确指定编码以避免令人讨厌的基于编码的错误。此外,流不是缓冲的。
所以你可能会更好
try (final Scanner scanner = new Scanner(new BufferedInputStream(new FileInputStream())), "UTF-8") {
//do stuff
}
丑陋,我知道。
值得注意的是Java 7提供了一个进一步的抽象层来消除循环文件的需要 - 这些都在Files类中:
byte[] Files.readAllBytes(Path path)
List<String> Files.readAllLines(Path path, Charset cs)
这两种方法都将整个文件读入内存,这可能不合适。在Java 8中,通过添加对新Stream
API的支持来进一步改进:
Stream<String> Files.lines(Path path, Charset cs)
Stream<Path> Files.list(Path dir)
例如,您可以从Path
获取Stream个字词:
final Stream<String> words = Files.lines(Paths.get("myFile.txt")).
flatMap((in) -> Arrays.stream(in.split("\\b")));
答案 1 :(得分:3)
SCANNER:
可以使用正则表达式解析基本类型和字符串。 扫描程序使用分隔符模式将其输入分解为标记,分隔符模式默认匹配空格。然后可以将生成的标记转换为不同类型的值。更多可以在http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
处读取 DATA INPUT STREAM:
允许应用程序以与机器无关的方式从基础输入流中读取原始Java数据类型。应用程序使用数据输出流来写入数据,以后可以通过数据输入流读取数据。对于多线程访问,DataInputStream不一定是安全的。线程安全是可选的,是本课程中方法用户的责任。可以在http://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html
阅读更多内容 BufferedReader:
从字符输入流中读取文本,缓冲字符,以便有效地读取字符,数组和行。可以指定缓冲区大小,或者可以使用默认大小。对于大多数目的,默认值足够大。通常,由Reader构成的每个读取请求都会导致相应的读取请求由基础字符或字节流组成。因此,建议将BufferedReader包装在任何read()操作可能代价高昂的Reader上,例如FileReaders和InputStreamReaders。例如,
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
将缓冲指定文件的输入。如果没有缓冲,read()或readLine()的每次调用都可能导致从文件中读取字节,转换为字符,然后返回,这可能是非常低效的。使用DataInputStreams进行文本输入的程序可以通过替换每个来进行本地化具有适当的BufferedReader.More详细信息的DataInputStream位于http://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html
答案 2 :(得分:0)
注意:此方法已过时。正如鲍里斯在评论中指出的那样。我将把它留在历史记录中,但你应该使用JDK中提供的方法。
这取决于您正在进行的操作类型以及您正在阅读的文件的大小。
在大多数情况下,我建议将commons-io用于小文件。
byte[] data = FileUtils.readFileToByteArray(new File("myfile"));
您可以将其读作字符串或字符数组......
现在,您正在处理大文件,或直接在文件系统上更改文件的某些部分,然后最好使用RandomAccessFile,甚至可能使用FileChannel来执行“nio”样式。