在Java中读取一个纯文本文件
在Java中似乎有不同的方法来读写文件数据。
我想从一个文件中读取ASCII数据。有哪些可能的方法和它们的区别?
899
20
在Java中似乎有不同的方法来读写文件数据。
我想从一个文件中读取ASCII数据。有哪些可能的方法和它们的区别?
我最喜欢的读取小文件的方法是使用一个BufferedReader和一个StringBuilder。它非常简单,而且一针见血(虽然不是特别有效,但对大多数情况来说已经很好了)。
有人指出,在Java 7之后,你应该使用try-with-resources(即自动关闭)的功能。
当我阅读这样的字符串时,我通常希望无论如何都要对每一行做一些字符串处理,所以就会选择这种实现。
如果我想把一个文件读成一个字符串,我总是使用Apache Commons IO 的IOUtils.toString()方法。你可以看看这里的源代码。
http://www.docjar.com/html/api/org/apache/commons/io/IOUtils.java.html
而用Java 7就更简单了。
ASCII是一个TEXT文件,所以你可以使用
Readers
来读取。Java也支持使用InputStreams
从二进制文件读取。如果被读取的文件很大,那么你会想在FileReader
的基础上使用BufferedReader
来提高读取性能。通过这篇文章了解如何使用 "读取器"。
我还建议你下载并阅读这本名为Thinking In Java的精彩(免费)书籍。
在Java 7中。
(docs) 或
(docs)
在Java 8中。
(docs)
最简单的方法是使用Java中的
Scanner
类和FileReader对象。简单的例子。Scanner
有几种方法可以读入字符串、数字等...。你可以在Java文档页面上寻找更多这方面的信息。例如,将整个内容读入一个
String
。另外,如果你需要一个特定的编码,你可以用它来代替
FileReader
。这里有一个简单的解决方案。
下面是另一种不用外部库的方法。
我不得不对不同的方式进行基准测试。 我将对我的发现进行评论,但简而言之,最快的方式是使用普通的BufferedInputStream而不是FileInputStream。 如果必须读取许多文件,那么三个线程将使总的执行时间减少到大约一半,但增加更多的线程将逐渐降低性能,直到使使用二十个线程完成的时间是只使用一个线程的三倍。
假设你必须读取一个文件,并对其内容做一些有意义的事情。 在这里的例子中,是从一个日志中读取行,并计算其中包含超过某个阈值的值。 所以我假设单行的Java 8
Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";"))
不是一个选项。我在Java 1.8、Windows 7以及SSD和HDD驱动器上进行了测试。
我写了六个不同的实现。
rawParse: 在FileInputStream上使用BufferedInputStream,然后一字节一字节地切行读取。 这优于任何其他单线程方法,但对于非ASCII文件来说可能非常不方便。
lineReaderParse。 在FileReader之上使用BufferedReader,逐行读取,通过调用String.split()来分割行。 这比rawParse慢了近20%。
lineReaderParseParallel: 这与lineReaderParse相同,但它使用了多个线程。 在所有情况下,这都是最快的选项。
nioFilesParse:使用java.nio.filesParse。 使用java.nio.files.Files.lines()
nioAsyncParse.使用一个带有完成处理程序和线程池的异步文件通道。 使用一个异步文件通道,带有一个完成处理程序和一个线程池。
nioMemoryMappedParse: 使用一个内存映射的文件. 这是一个很糟糕的想法,它的执行时间至少是其他实现的三倍。
这些是在四核i7和SSD驱动器上读取204个文件的平均时间,每个文件4 MB。 这些文件是在飞行中生成的,以避免磁盘缓存。
我发现在SSD或HDD驱动器上运行的差异比我预期的要小,SSD大约快15%。 这可能是因为文件是在无碎片的HDD上生成的,而且它们是按顺序读取的,因此旋转的硬盘几乎可以像SSD一样执行。
我对nioAsyncParse实现的低性能感到惊讶。 要么是我以错误的方式实现了某些东西,要么是使用NIO和一个完成处理程序的多线程实现的性能与使用java.io API的单线程实现相同(甚至更差)。 而且使用完成处理程序的异步解析比直接在老流上实现的代码行数要长得多,而且正确实现起来也很棘手。
现在,这六个实现之后是一个包含它们的类,再加上一个可参数化的main()方法,可以玩转文件数量、文件大小和并发程度。 请注意,文件的大小会有正负20%的变化。 这是为了避免由于所有文件的大小完全相同而造成的任何影响。
rawParse
以下是三种工作和测试方法。
使用
BufferedReader
。使用 "扫描器"。
使用
FileReader
。使用
Scanner
类无循环地读取整个文件。org.apache.commons.io.FileUtils
中的方法也很方便,例如你想用这些文字做什么? 文件小到可以放入内存吗? 我会尝试找到最简单的方法来处理文件,以满足你的需求。 FileUtils 库可以很好地处理这个问题。
我记录了[15种在Java中读取文件的方法][1],然后测试了它们在不同文件大小下的速度--从1 KB到1 GB,以下是三大方法。
java.nio.file.Files.readAllBytes()
。经测试可在Java 7、8和9中工作。
导入java.io.File.IOException;。 import java.io.IOException; import java.nio.file.Files.Files;
公共类ReadFile_Files_ReadAllBytes {。 public static void main(String [] pArgs) throws IOException {。 String fileName = "c:\temp\sample-10KB.txt"。 File file = new File(fileName);
byte [] fileBytes = Files.readAllBytes(file.toPath()); file.toPath() for(byte b : fileBytes) { = file.toPath(); char singleChar; for(byte b : fileBytes) singleChar = (char) b; System.out.print(singleChar); } } }
java.io.BufferedReader.readLine()
。经测试可在Java 7、8、9中工作。
import java.io.BufferedReader; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader; import java.io.FileReader。 import java.io.FileReader; import java.io.IOException;
public class ReadFile_BufferedReader_ReadLine { public static void main(String [] args) throws IOException {。 String fileName = "c:\temp\sample-10KB.txt"。 FileReader fileReader = new FileReader(fileName)。
try (BufferedReader bufferedReader = new BufferedReader(fileReader)) { 字符串line.readLine()) != null while((line = bufferedReader.readLine()) != null) { System.out.println(line); } } } }
java.nio.file.Files.lines()
。这个测试在Java 8和9中工作,但在Java 7中不能工作,因为有lambda表达式的要求。
import java.io.File.IOException; import java.io.IOException; import java.IO.IOException; import java.IO.IOException; import java.IO.IOException; import java.IO.IOException; import java.IO.IOException; import java.IO.IOException。 import java.io.IOException; import java.nio.file.Files.Files; import java.util.stream.Stream;
public class ReadFile_Files_Lines { public static void main(String[]pArgs) throws IOException { String fileName = "c:\temp\sample-10KB.txt"。 File file = new File(fileName)。
try (Stream linesStream = Files.lines(file.toPath())) { linesStream.forEach(line -> { System.out.println(line); }); } } }
[1]: https://funnelgarden.com/java_read_file
下面是用Java 8的方式做的单行本。 假设
text.txt
文件在Eclipse的项目目录的根目录下。这基本上和Jesus Ramos'.的回答完全一样,只是用File代替了FileReader,再加上迭代来浏览文件内容。 答案完全一样,只是用File代替了FileReader,再加上迭代来遍历文件的内容。
... 抛出 "FileNotFoundException"。
使用BufferedReader。
可能没有缓冲I/O的速度快,但很简洁。
Z
模式告诉扫描器
,定界符是EOF。缓冲流类在实践中的性能更强,以至于NIO.2 API包含了专门返回这些流类的方法,部分原因是为了鼓励你在应用中始终使用缓冲流。
下面是一个例子。
你可以替换这段代码
与
笔者推荐本篇文章,学习Java NIO和IO的主要用途。
在Java中从文件中读取数据最简单的方法就是利用File类来读取文件,利用Scanner类来读取文件的内容。
到目前为止,我还没看到其他答案中提到。 但如果"Best"。 意味着速度,那么新的Java I/O(NIO)可能会提供最快的性能,但对于学习的人来说,并不总是最容易弄清楚。
http://download.oracle.com/javase/tutorial/essential/io/file.html
你可以使用readAllLines和
join
方法在一行中获取整个文件内容。它默认使用UTF-8编码,可以正确读取ASCII数据。
此外,您也可以使用readAllBytes。
我认为readAllBytes更快、更精确,因为它不会用
n`代替新行,而且新行也可能是
r/n`。 这取决于你的需求,哪一个是合适的。这可能不是问题的确切答案。 它只是另一种读取文件的方式,在这种方式下,你不在Java代码中明确指定文件的路径,而是将其作为命令行参数来读取。
用下面的代码。
只是去运行它与。
这将读取
input.txt
的内容,并将其打印到你的控制台。你也可以让你的
System.out.println()
通过命令行写到一个特定的文件,如下所示。这将从 "input.txt "读取并写入 "output.txt"。
番石榴][1]为此提供了一个单行本。
[1]: https://en.wikipedia.org/wiki/Google_Guava