Java读取文件的方法不同

似乎有很多很多方法可以在Java中读取文本文件( BufferedReaderDataInputStream等)。我个人最喜欢的是在构造函数中使用File Scanner (它更简单,更好地处理mathy数据处理,并且具有熟悉的语法) 。

Boris the Spider还提到了ChannelRandomAccessFile

有人可以解释这些方法的优点和缺点吗? 具体来说,我什么时候想要使用?

(编辑)我想我应该是具体的,并补充说我非常喜欢Scanner方法。 所以真正的问题是,什么时候不想使用它?

让我们从头开始。 问题是你想做什么?

了解文件的实际内容非常重要。 文件是光盘上的字节集合,这些字节是您的数据。 Java提供了各种级别的抽象:

  1. File(Input|Output)Stream – 将这些字节读取为byte流。
  2. File(Reader|Writer) – 从字节流中读取char作为流。
  3. Scanner – 从char流中读取并标记它。
  4. RandomAccessFile – 将这些字节读取为可搜索的byte[]
  5. FileChannel – 以安全的multithreading方式读取这些字节。

除了每个之外还有装饰器 ,例如你可以使用BufferedXXX添加缓冲。 您可以使用PrintWriter将换行感知添加到FileWriter 。 您可以使用InputStreamInputStream转换为Reader (当前是为Reader指定字符编码的唯一方法)。

那么 – 我什么时候不想使用它[ Scanner ]?

如果你愿意,你不会使用Scanner (这些是一些例子):

  1. byte s读入数据
  2. 读入序列化的Java对象
  3. 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 Files.readAllLines(Path path, Charset cs) 

这两种方法都将整个文件读入内存,这可能不合适。 在Java 8中,通过添加对新Stream API的支持进一步改进了这一点:

 Stream Files.lines(Path path, Charset cs) Stream Files.list(Path dir) 

例如,要从Path获取单词流 ,您可以执行以下操作:

  final Stream words = Files.lines(Paths.get("myFile.txt")). flatMap((in) -> Arrays.stream(in.split("\\b"))); 

SCANNER:

可以使用正则表达式解析基本类型和字符串。 扫描程序使用分隔符模式将其输入分解为标记,分隔符模式默认匹配空格。 然后可以将生成的标记转换为不同类型的值。更多信息可以在http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html上阅读。

DATA INPUT STREAM:

允许应用程序以与机器无关的方式从基础输入流中读取原始Java数据类型。 应用程序使用数据输出流来写入数据,以后可以通过数据输入流读取数据。对于multithreading访问,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

注意:此方法已过时。 正如鲍里斯在评论中指出的那样。 我将把它保留在历史记录中,但您应该使用JDK中提供的方法。

这取决于您正在进行的操作类型以及您正在阅读的文件的大小。

在大多数情况下,我建议使用commons-io来处理小文件。

 byte[] data = FileUtils.readFileToByteArray(new File("myfile")); 

你可以把它读成字符串或字符数组……

现在,您正在处理大文件,或直接在文件系统上更改文件的某些部分,然后最好使用RandomAccessFile,甚至可能使用FileChannel来执行“nio”样式。