如何在Java中逐行读取文件
如何在Java中逐行读取文件
本文翻译自 How to read a file line by line in Java
有时我们想逐行读取一个文件来处理内容。 一个很好的例子是 逐行读取CSV文件 ,然后将其用逗号(,)分成多列。
在Java中,当您需要逐行读取文件时,有多种选项可供选择。
1.Scanner
Scanner
类提供了用Java逐行读取文件的最简单方法。 我们可以使用Scanner类打开文件,然后逐行读取其内容。
Scanner程序使用定界符模式将其输入分为令牌,在本例中为新行:
try {
// open file to read
Scanner scanner = new Scanner(new File("examplefile.txt"));
// read until end of file (EOF)
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
// close the scanner
scanner.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
如果此扫描程序的输入中有另一行而不推进文件读取位置,则
hasNextLine()
方法将返回
true
。
要读取数据并移至下一行,我们应使用
nextLine()
方法。 此方法将扫描仪移到当前行之后,并返回当前行的其余部分,但不包括最后的任何行分隔符。 然后将读取位置设置为下一行的开头。
由于
nextLine()
方法继续在输入中搜索以寻找行分隔符,因此如果不存在行分隔符,它可以缓冲所有要搜索的输入以跳过该行。
2. BufferedReader
BufferedReader类提供了一种从字符输入流中读取字符,数组和行的有效方法。
顾名思义,它最多可缓冲8MB(或8192KB)的字符,对于大多数用例而言,这足够大。 如果您正在读取的文件大于默认缓冲区大小,则可以自定义默认大小:
BufferedReader br = new BufferedReader(new FileReader(" foo.txt"), size);
BufferedReader
构造函数接受一个
Reader
实例(如
FileReader
,
InputStreamReader
)作为字符输入流源。 这是一个简单的示例,显示了如何使用它逐行读取文件:
try {
// create a reader instance
BufferedReader br = new BufferedReader(new FileReader("examplefile.txt"));
// read until end of file
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
// close the reader
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
readLine()
方法从文件中读取一行文本,并返回一个包含该行内容的字符串,但不包括任何行终止字符或null。
注意
:null值并不表示字符串为空。 而是表明已到达文件末尾。
另外,您可以使用
BufferedReader
类中的
lines()
方法返回行流。 您可以轻松地将此流转换为列表或阅读以下内容:
try {
// create a reader instance
BufferedReader br = new BufferedReader(new FileReader("examplefile.txt"));
// list of lines
List<String> list = new ArrayList<>();
// convert stream into list
list = br.lines().collect(Collectors.toList());
// print all lines
list.forEach(System.out::println);
// close the reader
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
3. Java 8 Stream
Java 8 Stream是另一种逐行读取文件的方式(尽管更干净)。 我们可以使用
Files.lines()
静态方法来初始化行流,如下所示:
try {
// initialize lines stream
Stream<String> stream = Files.lines(Paths.get("examplefile.txt"));
// read lines
stream.forEach(System.out::println);
// close the stream
stream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
4. New I/O API
Java新的I/O API或NIO(java.nio.*包中的类)提供了
Files.readAllLines()
方法来将文本文件逐行读取到
List <String>
中,如下所示:
try {
// read all lines
List<String> lines = Files.readAllLines(Paths.get("examplefile.txt"));
// print all lines
lines.forEach(System.out::println);
} catch (IOException ex) {
ex.printStackTrace();
}
5. RandomAccessFile
RandomAccessFile类提供读写文件的非阻塞模式。 随机访问文件的行为类似于存储在文件系统中的大字节数组。
我们可以使用
RandomAccessFile
以读取模式打开文件,然后使用其
readLine()
方法逐行读取:
try {
// open file in read mode
RandomAccessFile file = new RandomAccessFile("examplefile.txt", "r");
// read until end of file
String line;
while ((line = file.readLine()) != null) {
System.out.println(line);
// close the file
file.close();
} catch (IOException ex) {
ex.printStackTrace();
}
6. Apache Commons IO
Apache Commons IO库包含实用程序类,流实现,文件过滤器,文件比较器等。 将以下内容添加到
build.gradle
文件中,以将库导入项目中:
implementation 'commons-io:commons-io:2.6'
如果您使用的是Maven,请将以下内容添加到·pom.xml·文件中:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
现在,我们可以使用
FileUtils.readLines()
(来自Apache Commons IO的静态方法)将文件中的所有行读取到
List <String>
中:
try {
// read all lines of a file
List<String> lines = FileUtils.readLines(Paths.get("examplefile.txt").toFile(), "UTF-8");
// process the lines
for (String line : lines) {
System.out.println(line);
} catch (IOException ex) {
ex.printStackTrace();
}
由于Apache Commons IO一次读取文件中的所有行,因此对于读取大文件而言,这可能不是一个好的解决方案。 在上述情况下,它将继续阻止for循环执行,直到将所有行添加到
lines
对象为止。
7.Okie
Okie
是由Square为Android,Kotlin和Java开发的另一个开源I/O库。 它补充了本机
java.io
和
java.nio
包,使访问,保存和处理数据变得更加容易。
要在项目中导入Okie,请将以下内容添加到build.gradle文件中:
implementation 'com.squareup.okio:okio:2.4.0'
如果您使用的是Maven,请将以下内容添加到
pom.xml
文件中:
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>2.4.0</version>
</dependency>
现在,我们可以使用
Okio.source()
方法打开源流以读取文件。 返回的
Source
接口很小,用途有限。
Okie
提供了
BufferedSource
类来用缓冲区包装源,从而使程序运行更快。
让我们举个例子:
try {
// open a source stream
Source source = Okio.source(Paths.get("examplefile.txt").toFile());
// wrap stream with a buffer
BufferedSource bs = Okio.buffer(source);
// read until end of file
String line;
while ((line = bs.readUtf8Line()) != null) {
System.out.println(line);
// close the stream
source.close();