杰瑞科技汇

BufferedReader如何高效读取Java文本文件?

这是一个非常基础且重要的 I/O 类,理解它对于进行高效的文件读取和网络数据读取至关重要。

BufferedReader如何高效读取Java文本文件?-图1
(图片来源网络,侵删)

什么是 BufferedReader

BufferedReader 是 Java I/O 包 (java.io) 中的一个类,它的主要作用是为字符输入流提供一个缓冲区

它就像一个“蓄水池”:

  • 没有缓冲区:你需要一杯水,就直接去水龙头接一杯,频繁地去接水龙头开关,效率很低。
  • 有缓冲区:你先打开水龙头,把水蓄满一个水池,之后你需要水,就直接从水池里舀,非常快,水池满了之后,再一次性去打开水龙头蓄水。

BufferedReader 就是这个“水池”,它内部维护了一个字符数组(即缓冲区),当读取数据时,它会一次性从底层输入流(如 FileReader)中读取一大块数据到缓冲区中,之后,程序每次调用 read() 方法时,都是从内存中的这个缓冲区读取,而不是直接访问慢速的磁盘或网络,从而极大地提高了读取效率。


核心优点:为什么使用它?

性能提升:这是 BufferedReader 最核心的优点,I/O 操作(尤其是磁盘和网络 I/O)是非常耗时的,通过减少直接进行 I/O 操作的次数,BufferedReader 能显著提高程序的性能。

BufferedReader如何高效读取Java文本文件?-图2
(图片来源网络,侵删)

示例对比: 假设你要从一个文件中读取 1000 个字符。

  • 不使用 BufferedReaderFileReader 可能会进行 1000 次磁盘读取操作(每次读一个字符)。
  • 使用 BufferedReaderBufferedReader 会一次性从 FileReader 中读取 8192 个字符(默认缓冲区大小)到内存,你的程序可以从内存中连续读取 1000 个字符,而 FileReader 的磁盘读取操作可能只有 1 次。

如何使用 BufferedReader

BufferedReader 本身不能直接读取文件或网络数据,它必须包装一个底层字符输入流

基本构造方法

  1. BufferedReader(Reader in):创建一个默认缓冲区大小(通常是 8192 字节)的缓冲字符输入流。
  2. BufferedReader(Reader in, int sz):创建一个指定缓冲区大小的缓冲字符输入流。

常用方法

方法 描述
int read() 读取单个字符,返回读取的字符(0-65535 的 int 值),如果已到达流末尾,则返回 -1
int read(char[] cbuf, int off, int len) 将字符读入一个数组的一部分,这是最常用的读取方法之一。
String readLine() 读取一行文本,该方法会读取直到遇到换行符 \n、回车符 \r 或两者组合 \r\n,返回读取的字符串(不包含换行符),如果已到达流末尾,则返回 null这是 BufferedReader 最著名、最常用的方法。
long skip(long n) 跳过 n 个字符。
boolean ready() 判断此流是否已准备好被读取(即缓冲区中是否有数据)。
void close() 关闭流,并释放与该流关联的所有系统资源。非常重要!

代码示例

示例 1:从文件中逐行读取

这是 BufferedReader 最经典、最常见的用法,我们需要结合 FileReader 来使用。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {
    public static void main(String[] args) {
        // 使用 try-with-resources 语句,可以自动关闭资源,避免资源泄漏
        // 这是 Java 7 及以上版本推荐的最佳实践
        try (BufferedReader reader = new BufferedReader(new FileReader("my_file.txt"))) {
            String line;
            // readLine() 在读取到文件末尾时会返回 null
            // 所以我们可以用 while (line != null) 来循环
            while ((line = reader.readLine()) != null) {
                // 处理每一行内容
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码解析

BufferedReader如何高效读取Java文本文件?-图3
(图片来源网络,侵删)
  1. new FileReader("my_file.txt"):创建一个 FileReader,它是底层流,负责直接从文件中读取字节并将其解码为字符。
  2. new BufferedReader(...):将 FileReader 包装起来,创建一个带缓冲区的 BufferedReader
  3. try-with-resources: 中的资源会在 try 代码块执行完毕后自动调用 close() 方法,即使发生异常也能确保关闭,是现代 Java 编程的标准做法。
  4. reader.readLine():循环调用此方法,每次读取文件的一行,直到文件末尾返回 null

示例 2:从控制台读取用户输入

System.in 是一个 InputStream(字节流),我们需要用 InputStreamReader 将其转换为 Reader(字符流),然后再用 BufferedReader 包装。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ConsoleInputExample {
    public static void main(String[] args) {
        // System.in 是 InputStream
        // InputStreamReader 将 InputStream 转换为 Reader
        // BufferedReader 包装 Reader 以提供缓冲和 readLine() 方法
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入您的名字,输入 'exit' 退出:");
        try {
            String userInput;
            while ((userInput = reader.readLine()) != null) {
                if ("exit".equalsIgnoreCase(userInput)) {
                    System.out.println("程序退出。");
                    break;
                }
                System.out.println("你好, " + userInput + "!");
                System.out.println("请继续输入: ");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 一定要手动关闭,因为 System.in 是系统资源
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

重要注意事项

必须关闭流

BufferedReader 底层会持有系统资源(如文件句柄、网络连接),如果不关闭这些资源,会导致资源泄漏,最终可能导致程序崩溃(打开的文件数量达到系统上限)。

最佳实践:始终使用 try-with-resources 语句,它可以自动处理资源的关闭。

readLine() 的一个“陷阱”

readLine() 方法在读取一行后,不会将行终止符(\n\r\n)包含在返回的字符串中,这是一个常见的设计,但也需要注意。

BufferedReader vs Scanner

很多初学者会混淆 BufferedReaderScanner,它们都可以用来读取输入,但有显著区别:

特性 BufferedReader Scanner
底层 基于 Reader(字符流) 基于 InputStream(字节流)
性能 非常快,专为高效读取设计 较慢,因为它有更复杂的解析逻辑(如正则表达式)
主要功能 高效读取文本行 解析原始类型和字符串(如 nextInt(), nextDouble()
线程安全
分隔符 固定为换行符 \n, \r, \r\n 可自定义(默认是空白字符:空格、Tab、换行等)

选择建议

  • 如果只是高效地逐行读取文本(如文件、控制台),首选 BufferedReader
  • 如果需要从输入中解析出数字、日期等原始类型,或者需要灵活的分隔符,Scanner 更方便。

BufferedReader 是 Java 开发者工具箱中一个不可或缺的工具,它的核心价值在于通过缓冲机制提升 I/O 性能

记住以下几点:

  1. 它是一个包装器:必须配合 Reader(如 FileReader, InputStreamReader)使用。
  2. readLine() 是王牌:这是它最常用、最方便的方法。
  3. 性能为王:在处理大文件或需要频繁读取的场景下,性能优势明显。
  4. 资源管理要牢记:使用 try-with-resources 来确保流被正确关闭。
  5. Scanner 区分:需要解析原始类型用 Scanner,需要高效读取纯文本用 BufferedReader
分享:
扫描分享到社交APP
上一篇
下一篇