ZetCode

Java Reader 类

最后修改时间:2025 年 4 月 16 日

java.io.Reader 类是一个用于读取字符流的抽象类。它是 Java 中所有字符输入流类的基类。与字节流不同,Reader 处理 16 位 Unicode 字符。

Reader 提供了从各种源读取字符的基本方法。子类实现这些方法以用于特定的输入类型,如文件、字符串或管道。该类在内部处理字符编码转换。

Reader 类概述

Reader 是一个抽象类,定义了基本的字符输入操作。关键方法包括读取字符、跳过字符以及 mark/reset 功能。 所有方法都会抛出 IOException 以表示 I/O 错误。

public abstract class Reader implements Readable, Closeable {
    public int read();
    public int read(char[] cbuf);
    public abstract int read(char[] cbuf, int off, int len);
    public long skip(long n);
    public boolean ready();
    public boolean markSupported();
    public void mark(int readAheadLimit);
    public void reset();
    public abstract void close();
}

上面的代码显示了 Reader 提供的关键方法。 这些方法允许从各种来源读取字符数据。 具体子类必须实现用于特定输入类型的抽象方法。

创建 Reader

Reader 是抽象的,因此我们使用其子类,如 FileReader 或 StringReader。 这些为不同的字符源提供了具体的实现。 完成后始终关闭 Reader 以释放资源。

Main.java
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Main {

    public static void main(String[] args) {
        try {
            // Create FileReader
            Reader fileReader = new FileReader("text.txt");
            
            // Create StringReader
            Reader stringReader = new StringReader("Hello Reader");
            
            System.out.println("FileReader and StringReader created");
            
            fileReader.close();
            stringReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了创建两个常见的 Reader 实现。 FileReader 从文件读取,而 StringReader 从字符串读取。 两者都是 Reader 的子类。 close 方法释放所有系统资源。

使用 Reader 读取字符

读取字符的最简单方法是使用 read() 方法。 它以 int 形式返回单个字符,如果到达流末尾则返回 -1。 这对于逐字符处理文本很有用。

Main.java
import java.io.IOException;
import java.io.StringReader;
import java.io.Reader;

public class Main {

    public static void main(String[] args) {
        try (Reader reader = new StringReader("Java Reader")) {
            
            int charData;
            while ((charData = reader.read()) != -1) {
                System.out.print((char) charData);
            }
            
            System.out.println("\n\nReading complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何从 StringReader 中逐个字符读取。 try-with-resources 语句确保正确关闭流。 每个字符都从 int 强制转换为 char 以进行显示。 循环持续到 read 返回 -1。

将字符读取到数组中

为了获得更好的性能,一次将多个字符读入一个 char 数组。 这减少了方法调用并提高了效率。 read 方法返回实际读取的字符数。

Main.java
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Main {

    public static void main(String[] args) {
        try (Reader reader = new FileReader("text.txt")) {
            
            char[] buffer = new char[1024];
            int charsRead;
            
            while ((charsRead = reader.read(buffer)) != -1) {
                System.out.println("Read " + charsRead + " characters");
                System.out.println(new String(buffer, 0, charsRead));
            }
            
            System.out.println("File reading complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了批量读取到 char 数组中。 可以根据需要调整缓冲区大小 (1024)。 charsRead 值指示实际读取了多少字符。 String 构造函数将缓冲区的相关部分转换为字符串。

Mark 和 Reset 功能

某些 Reader 实现支持 mark 和 reset 操作以重新读取数据。 mark 方法标记当前位置,reset 返回到该位置。 readAheadLimit 指定在 mark 变为无效之前可以读取多少个字符。

Main.java
import java.io.IOException;
import java.io.StringReader;
import java.io.Reader;

public class Main {

    public static void main(String[] args) {
        try (Reader reader = new StringReader("Java Reader Mark Example")) {
            
            // Read first 5 characters
            char[] firstPart = new char[5];
            reader.read(firstPart);
            System.out.println("First part: " + new String(firstPart));
            
            // Mark current position
            reader.mark(10); // Allow 10 chars to be read before mark invalid
            
            // Read next 5 characters
            char[] secondPart = new char[5];
            reader.read(secondPart);
            System.out.println("Second part: " + new String(secondPart));
            
            // Reset back to mark
            reader.reset();
            
            // Read again from marked position
            reader.read(secondPart);
            System.out.println("Second part after reset: " + new String(secondPart));
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了 StringReader 的 mark 和 reset 功能。 在读取前 5 个字符后设置 mark。 读取接下来的 5 个字符后,reset 返回到标记的位置。 并非所有 Reader 都支持 mark/reset - 请使用 markSupported() 检查。

跳过流中的字符

skip 方法允许跳过流中指定数量的字符。 这比读取和丢弃数据更有效。 实际跳过的字符数可能少于请求的字符数。

Main.java
import java.io.IOException;
import java.io.StringReader;
import java.io.Reader;

public class Main {

    public static void main(String[] args) {
        try (Reader reader = new StringReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
            
            // Skip first 10 characters
            long skipped = reader.skip(10);
            System.out.println("Skipped " + skipped + " characters");
            
            // Read next character
            int nextChar = reader.read();
            System.out.println("Next character: " + (char) nextChar);
            
            // Skip beyond end of stream
            skipped = reader.skip(20);
            System.out.println("Skipped " + skipped + " characters (end approached)");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何在 Reader 中跳过字符。 第一个 skip 越过前 10 个字母。 第二个 skip 尝试跳过 20 个字符,但仅跳过剩余的字符。 该方法返回实际跳过的数量。

使用 ready() 检查就绪状态

ready 方法检查 Reader 是否已准备好读取。 如果下一次读取不会阻塞输入,则返回 true。 这对于非阻塞 I/O 检查很有用。

Main.java
import java.io.IOException;
import java.io.StringReader;
import java.io.Reader;

public class Main {

    public static void main(String[] args) {
        try (Reader reader = new StringReader("Ready Check")) {
            
            System.out.println("Reader ready: " + reader.ready());
            
            // Read all characters
            while (reader.ready()) {
                System.out.print((char) reader.read());
            }
            
            System.out.println("\nReader after reading: " + reader.ready());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了使用 ready() 检查 Reader 状态。 当字符可用时,该方法返回 true。 读取所有字符后,ready() 返回 false。 请注意,返回 false 并不一定意味着流的结尾。

来源

Java Reader 类文档

在本文中,我们介绍了 Java Reader 类的基本方法和功能。 理解这些概念对于在 Java 应用程序中使用字符输入操作至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的专业程序员。 我于 2007 年开始撰写编程文章,至今已撰写超过 1,400 篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程