让我们从头开始。问题是你想做什么?
了解文件的实际含义非常重要。文件是光盘上的字节集合,这些字节是您的数据。Java在上面提供了各种抽象级别:
-
File(Input|Output)Stream
- 将这些字节读取为 .byte
-
File(Reader|Writer)
- 从字节流读取为 .char
-
Scanner
- 从流中读取并标记它。char
-
RandomAccessFile
- 将这些字节读取为可搜索的.byte[]
-
FileChannel
- 以安全的多线程方式读取这些字节。
在每个装饰器之上,例如,您可以使用 添加缓冲。您可以将换行符感知添加到 with .您可以将 a 转换为 带有 a(目前为 a 指定字符编码的唯一方法)。BufferedXXX
FileWriter
PrintWriter
InputStream
Reader
InputStreamReader
Reader
那么 - 我什么时候不想使用它[扫描仪
]?
如果你愿意,你不会使用 a(这些是一些例子):Scanner
- 以 s 的形式读取数据
byte
- 在序列化的 Java 对象中读取
- 将 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中,通过添加对新API的支持,这一点得到了进一步的改进:Stream
Stream<String> Files.lines(Path path, Charset cs)
Stream<Path> Files.list(Path dir)
例如,要从 中获取单词流,您可以执行以下操作:Path
final Stream<String> words = Files.lines(Paths.get("myFile.txt")).
flatMap((in) -> Arrays.stream(in.split("\\b")));