1、概述
本教程将演示如何用Java高效地读取大文件。这篇文章是Baeldung(http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分。
2、在内存中读取
读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法:
1
2
3
|
Files.readLines( new File(path), Charsets.UTF_8);
FileUtils.readLines( new File(path));
|
这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致程序抛出OutOfMemoryError 异常。
例如:读取一个大约1G的文件:
1
2
3
4
5
|
@Test public void givenUsingGuava_whenIteratingAFile_thenWorks() throws IOException {
String path = ...
Files.readLines( new File(path), Charsets.UTF_8);
} |
这种方式开始时只占用很少的内存:(大约消耗了0Mb内存)
1
2
|
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 128 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 116 Mb
|
然而,当文件全部读到内存中后,我们最后可以看到(大约消耗了2GB内存):
1
2
|
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 2666 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 490 Mb
|
这意味这一过程大约耗费了2.1GB的内存——原因很简单:现在文件的所有行都被存储在内存中。
把文件所有的内容都放在内存中很快会耗尽可用内存——不论实际可用内存有多大,这点是显而易见的。
此外,我们通常不需要把文件的所有行一次性地放入内存中——相反,我们只需要遍历文件的每一行,然后做相应的处理,处理完之后把它扔掉。所以,这正是我们将要做的——通过行迭代,而不是把所有行都放在内存中。
3、文件流
现在让我们看下这种解决方案——我们将使用java.util.Scanner类扫描文件的内容,一行一行连续地读取:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
FileInputStream inputStream = null ;
Scanner sc = null ;
try {
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8" );
while (sc.hasNextLine()) {
String line = sc.nextLine();
// System.out.println(line);
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null ) {
throw sc.ioException();
}
} finally {
if (inputStream != null ) {
inputStream.close();
}
if (sc != null ) {
sc.close();
}
} |
这种方案将会遍历文件中的所有行——允许对每一行进行处理,而不保持对它的引用。总之没有把它们存放在内存中:(大约消耗了150MB内存)
1
2
|
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 763 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 605 Mb
|
4、Apache Commons IO流
同样也可以使用Commons IO库实现,利用该库提供的自定义LineIterator:
1
2
3
4
5
6
7
8
9
|
LineIterator it = FileUtils.lineIterator(theFile, "UTF-8" );
try {
while (it.hasNext()) {
String line = it.nextLine();
// do something with line
}
} finally {
LineIterator.closeQuietly(it);
} |
由于整个文件不是全部存放在内存中,这也就导致相当保守的内存消耗:(大约消耗了150MB内存)
1
2
|
[main] INFO o.b.java.CoreJavaIoIntegrationTest - Total Memory: 752 Mb
[main] INFO o.b.java.CoreJavaIoIntegrationTest - Free Memory: 564 Mb
|
5、结论
这篇短文介绍了如何在不重复读取与不耗尽内存的情况下处理大文件——这为大文件的处理提供了一个有用的解决办法。
相关推荐
"JAVA高效读取大文件" 概述:本文将讨论如何使用 Java 高效地读取大文件,解决读取大文件时可能遇到的 OutOfMemoryError 异常问题。同时,文章还将介绍使用 Guava 和 Apache Commons IO 库来读取大文件的不同方法,...
Java 高效读取大文件实例分析 在 Java 中高效读取大文件是一个非常重要的知识点,特别是在处理大规模数据的时候。今天,我们将讨论如何高效地读取大文件,避免出现OutOfMemoryError 异常。 概述 ----- 在 Java 中...
`Scanner`提供了更丰富的输入功能,但它不是为了处理大量数据而设计的,所以在处理大文件时,`BufferedReader`通常更高效。 在实际开发中,我们需要注意异常处理,例如在上述示例中使用了try-catch块来捕获可能抛出...
相较于传统的Java IO,NIO具有更高的性能和更丰富的功能,尤其适合处理大文件或高并发场景。 #### 二、Java NIO关键组件 Java NIO的核心组件包括: - **Channels**:用于表示IO源或目标的一个连接点。 - **Buffers*...
为了高效地处理这类问题,我们可以利用Java的`java.nio`包中的BufferedReader和FileChannel等类,实现按行读取大文件,并将其内容解析后存储到数据库中。本文将详细讲解这一过程。 首先,我们需要了解`java.nio`包...
在Java编程语言中,读取文件是一项常见的操作,尤其是在处理数据、日志文件或配置信息时。本文将详细解析如何使用Java读取文本文件,基于提供的代码示例,深入探讨其工作原理及最佳实践。 ### Java读取文本文件的...
java读取txt文件,可以以文件路径构造这个流,:FileInputStream fin = new FileInputStream("d:/test.txt"); 然后使用这个流直接读取到文件,再使用reader构造BufferedReader,按行读取一整行的文本,作为字符串返回...
在Java编程语言中,文件读取是常见的任务,可以用于处理各种类型的数据,如文本、图像、音频等。本文将详细介绍Java中四种不同的文件读取方法:按字节读取、按字符读取、按行读取以及随机读取。 1. **按字节读取...
它可以定位到文件的任意位置进行读写,非常适合处理大文件或需要频繁跳转的场景。使用`RandomAccessFile`时,需要传入文件路径和访问模式(如"r"表示只读,"rw"表示读写)。 3. **读取Java类文件**:要读取类文件,...
另一种高效读取大文件的方法是通过`FileChannel`和`ByteBuffer`的组合。这种方式也支持随机访问,并且可以通过调整缓冲区大小来适应不同的内存限制。 示例代码中演示了如何使用`ByteBuffer`和`FileChannel`读取文件...
Java使用多线程读取超大文件 Java使用多线程读取超大文件是指在java语言中使用多线程技术来读取超大文件,以提高读取速度和效率。下面是该技术的详细介绍和实现方法。 多线程读取超大文件的必要性 在读取超大文件...
本文将深入探讨如何使用Java来高效地读取大文件,并提供一个具体的示例代码进行说明。 #### 二、Java读取大文件的主要方法 在Java中,读取大文件主要有两种方式:传统IO流(如`FileInputStream`)和NIO(New IO)...
- Java提供`java.io`包中的`BufferedReader`类,用于高效地读取文本文件。首先,我们需要创建一个`FileReader`对象,指定要读取的TXT文件路径,然后通过`FileReader`创建`BufferedReader`对象。 - 使用`...
此外,由于GRIB2文件可能非常大,因此高效的数据流控制和内存管理也是需要注意的关键点。 总的来说,`netcdfAll`库为Java开发者提供了一个强大的工具,帮助他们处理GRIB2文件,而`ReadGrib2.java`示例则为初学者...
这里提供的jar文件`hdf5-3.3.2.jar`是Java接口库,它封装了对HDF5文件的操作,使得Java程序员可以通过调用Java API来实现读写HDF5文件。而`libjhdf.so.3.2.1`和`jhdf5.dll`分别是Linux和Windows平台的动态链接库,...
Java NIO(New IO)提供了非阻塞的I/O操作,可以更高效地处理文件读取: ```java Path path = Paths.get("config.properties"); Properties props = new Properties(); try (InputStream in = Files....
Java I/O提供了丰富的类和接口,如`InputStream`, `BufferedReader`, `FileReader`等,用于处理文件读写操作。在读取HTML文件时,我们通常会选择`BufferedReader`,因为它能高效地处理字符流并提供缓冲区以提高性能...
通过这种方法,Java程序能够高效地处理大文件,避免一次性加载整个文件导致的内存问题,同时通过缓冲区和内存映射文件优化了读取性能。这种方法尤其适用于处理非常大的文件,如日志文件或大数据分析中的文件。