ZetCode

Java PushbackReader 类

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

java.io.PushbackReader 类是一个字符流读取器,允许将字符推回流中。这在解析输入时提供了超前查看功能。它封装了另一个 Reader 并增加了推回能力。

PushbackReader 维护一个内部缓冲区用于推回的字符。读取时,推回的字符会首先返回,然后再从底层流中读取。默认的推回缓冲区大小为 1 个字符,但可以自定义。

PushbackReader 类概述

PushbackReader 扩展了 FilterReader 并提供了基于字符的推回操作。关键方法包括读取操作和 unread(推回)方法。该类对于需要超前查看的解析场景非常有用。

public class PushbackReader extends FilterReader {
    public PushbackReader(Reader in);
    public PushbackReader(Reader in, int size);
    public int read();
    public int read(char[] cbuf, int off, int len);
    public void unread(int c);
    public void unread(char[] cbuf);
    public void unread(char[] cbuf, int off, int len);
    public boolean ready();
    public void close();
}

上面的代码显示了 PushbackReader 提供的关键方法。unread 方法允许将字符推回流中。read 方法首先使用推回的字符,然后再从底层流中读取。

创建 PushbackReader

PushbackReader 通过将其封装在另一个 Reader 中创建。您可以指定缓冲区大小或使用默认值 (1 个字符)。缓冲区大小决定了可以推回多少个字符。

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

public class Main {

    public static void main(String[] args) {
        try {
            // Create with default buffer size (1 character)
            Reader fileReader = new FileReader("data.txt");
            PushbackReader pushbackReader1 = new PushbackReader(fileReader);
            
            // Create with custom buffer size (10 characters)
            Reader fileReader2 = new FileReader("data.txt");
            PushbackReader pushbackReader2 = 
                new PushbackReader(fileReader2, 10);
            
            System.out.println("Default pushback reader created");
            System.out.println("Custom pushback reader (size 10) created");
            
            pushbackReader1.close();
            pushbackReader2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了创建 PushbackReader 的不同方法。第一个使用默认缓冲区大小 (1 个字符),而第二个指定 10 个字符。完成操作后始终关闭读取器以释放资源。当关闭 PushbackReader 时,底层的 FileReader 会自动关闭。

读取和推回字符

PushbackReader 的基本操作包括读取字符并选择性地将它们推回。unread 方法将字符推回流中。随后的读取将首先返回这些字符。

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

public class Main {

    public static void main(String[] args) {
        String data = "ABCD";
        try (PushbackReader reader = 
                new PushbackReader(new StringReader(data))) {
            
            // Read first character
            int firstChar = reader.read();
            System.out.println("First character: " + (char) firstChar);
            
            // Push it back
            reader.unread(firstChar);
            System.out.println("Character pushed back");
            
            // Read again
            int sameChar = reader.read();
            System.out.println("Read again: " + (char) sameChar);
            
            // Read next character
            int nextChar = reader.read();
            System.out.println("Next character: " + (char) nextChar);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了基本的推回功能。读取第一个字符,然后将其推回,并再次读取。unread 方法允许将字符放回流中。推回缓冲区作为一个 LIFO(后进先出)结构运行。

推回多个字符

当使用更大的缓冲区创建时,PushbackReader 可以推回多个字符。unread 方法接受字符数组以进行批量推回操作。字符以它们在数组中出现的顺序被推回。

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

public class Main {

    public static void main(String[] args) {
        String data = "1234567890";
        try (PushbackReader reader = 
                new PushbackReader(new StringReader(data), 5)) {
            
            // Read first 5 characters
            char[] buffer = new char[5];
            reader.read(buffer);
            System.out.println("First read: " + new String(buffer));
            
            // Push them back
            reader.unread(buffer);
            System.out.println("5 characters pushed back");
            
            // Read again
            reader.read(buffer);
            System.out.println("Read again: " + new String(buffer));
            
            // Try to push back more than buffer size
            try {
                char[] bigBuffer = new char[6];
                reader.unread(bigBuffer); // Will throw IOException
            } catch (IOException e) {
                System.out.println("Cannot push back more than buffer size");
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了推回多个字符。读取器创建时带有 5 个字符的缓冲区。尝试推回超过缓冲区大小的字符会抛出 IOException。使用数组的 unread 操作对于批量推回场景非常有效。

使用 PushbackReader 进行解析

PushbackReader 特别适用于需要超前查看流的解析场景。检查字符后,如果它们与您要查找的内容不匹配,则可以将其推回。这使得解析逻辑更灵活。

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

public class Main {

    public static void main(String[] args) {
        String data = "123abc456";
        try (PushbackReader reader = 
                new PushbackReader(new StringReader(data), 3)) {
            
            StringBuilder numbers = new StringBuilder();
            int c;
            
            while ((c = reader.read()) != -1) {
                if (Character.isDigit((char) c)) {
                    numbers.append((char) c);
                } else {
                    // Push back non-digit and break
                    reader.unread(c);
                    break;
                }
            }
            
            System.out.println("Numbers found: " + numbers);
            
            // Read remaining characters
            char[] remaining = new char[6];
            reader.read(remaining);
            System.out.println("Remaining: " + new String(remaining));
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了 PushbackReader 如何用于解析。它读取数字,直到找到非数字,然后将其推回。这允许单独处理非数字。推回功能简化了许多解析任务。

处理 Mark 和 Reset

与其他一些读取器不同,PushbackReader 不支持 mark 和 reset 操作。尝试使用这些方法将导致异常。推回功能对于许多用例来说具有类似的目的。

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

public class Main {

    public static void main(String[] args) {
        String data = "test data";
        try (PushbackReader reader = 
                new PushbackReader(new StringReader(data))) {
            
            // Check if mark is supported
            System.out.println("Mark supported: " + reader.markSupported());
            
            // Try to mark (will not throw exception but does nothing)
            reader.mark(10);
            
            // Read some data
            int c = reader.read();
            System.out.println("Read: " + (char) c);
            
            // Try to reset (will throw IOException)
            try {
                reader.reset();
            } catch (IOException e) {
                System.out.println("Reset not supported: " + e.getMessage());
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了 PushbackReader 不支持 mark/reset。markSupported 方法返回 false。尝试 reset 会抛出 IOException。对于类似的功能,请使用推回功能而不是 mark/reset。

使用 Pushback 读取行

PushbackReader 可用于实现自定义行读取逻辑。此示例显示了如何在处理行结尾时一致地读取行。Pushback 有助于检查行结尾字符。

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

public class Main {

    public static void main(String[] args) {
        String data = "Line 1\r\nLine 2\nLine 3\rLine 4";
        try (PushbackReader reader = 
                new PushbackReader(new StringReader(data), 2)) {
            
            StringBuilder line = new StringBuilder();
            int c;
            
            while ((c = reader.read()) != -1) {
                if (c == '\n') {
                    System.out.println("Line found: " + line);
                    line.setLength(0);
                } else if (c == '\r') {
                    // Check for \r\n sequence
                    int next = reader.read();
                    if (next != '\n') {
                        reader.unread(next);
                    }
                    System.out.println("Line found: " + line);
                    line.setLength(0);
                } else {
                    line.append((char) c);
                }
            }
            
            // Print last line if not empty
            if (line.length() > 0) {
                System.out.println("Last line: " + line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例实现了自定义行读取,该读取处理不同的行结尾 (\n, \r, \r\n)。推回功能允许检查 \r 之后的字符,以确定它是否是 \r\n 序列的一部分。这演示了 PushbackReader 在文本处理中的实际应用。

来源

Java PushbackReader 类文档

在本文中,我们涵盖了 Java PushbackReader 类的基本方法和特性。了解这些概念对于处理需要在 Java 应用程序中具有超前查看能力的字符流至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在这一领域拥有多年的经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程