我可以偷看 BufferedReader 吗?

Posted

技术标签:

【中文标题】我可以偷看 BufferedReader 吗?【英文标题】:Can I peek on a BufferedReader? 【发布时间】:2011-01-31 20:06:02 【问题描述】:

有没有办法检查BufferedReader 对象中是否有要阅读的内容?类似于 C++ cin.peek()。谢谢。

【问题讨论】:

我感觉 C++ 的窥视和 Java 的窥视有歧义。 “检查是否有要读的东西”与 Java 中的“peek”不匹配。 【参考方案1】:

您可以使用PushbackReader。使用它,您可以读取一个字符,然后将其取消读取。这实际上允许您将其推回。

PushbackReader pr = new PushbackReader(reader);
char c = (char)pr.read();
// do something to look at c
pr.unread((int)c); //pushes the character back into the buffer

【讨论】:

好答案!这是 Java 的“窥视”。 您的Reader 可能正在返回代码点。您可能会通过截断一个值然后将其推回缓冲区来破坏流。 你能告诉我们数据是在流的末尾还是开始时推送的。只是确认,因为我觉得创建类似未读的东西,它会在缓冲区末尾推送字符会损坏数据,所以没有必要创建这样的东西。【参考方案2】:

你可以试试“boolean ready()”方法。 来自 Java 6 API 文档:“如果缓冲区不为空,或者基础字符流已准备好,则缓冲字符流已准备就绪。”

BufferedReader r = new BufferedReader(reader);
if(r.ready())

   r.read();

【讨论】:

【参考方案3】:

以下代码将查看 Stream 中的第一个字节。应该充当你的窥探。

BufferedReader bReader = new BufferedReader(inputStream);
bReader.mark(1);
int byte1 = bReader.read();
bReader.reset();

【讨论】:

但是你不想偷看,你想返回一个值? 是的,我确实想要一个 int peek()。如果流中有东西,我会通过检查返回值来得到答案,但流的状态不会改变。 @Thereisnothingwecando(我知道,7 岁……但对于阅读此书的其他人……)他的回答是真正的偷看等价物。实际上,您可以创建一个扩展 BufferedReader 的类,然后在这 3 行中添加 peek() 方法。瞧【参考方案4】:

如果BufferedReader#readLine() 不返回null,通常的习惯用法是循环检查。如果到达流的结尾(例如文件结尾、套接字关闭等),则返回null

例如

BufferedReader reader = new BufferedReader(someReaderSource);
String line = null;
while ((line = reader.readLine()) != null) 
    // ...

如果您不想逐行阅读(这是选择BufferedReader 的主要原因),请改用BufferedReader#ready()

BufferedReader reader = new BufferedReader(someReaderSource);
while (reader.ready()) 
    int data = reader.read();
    // ...

【讨论】:

【参考方案5】:
BufferedReader br = new BufferedReader(reader);
br.mark(1);
int firstByte = br.read();
br.reset();

【讨论】:

【参考方案6】:

您可以使用PushBackReader 读取一个字符,然后将其“推回”。这样您就可以确定某物在那里,而不会影响其整体状态——“窥视”。

【讨论】:

pushbackreader 是如何工作的,我猜它会在缓冲区读取开始时推送数据,这将保持消息的整体状态,从而避免数据包损坏【参考方案7】:

来自 pgmura 的答案(依赖于 ready() 方法)很简单且有效。 但请记住,这是因为 Sun 的方法实现;这并不真正同意文档。如果这种行为很关键,我不会依赖它。 见这里http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4090471 我宁愿选择 PushbackReader 选项。

【讨论】:

【参考方案8】:

我的解决方案是.. 扩展 BufferedReader 并将队列用作 buf,然后您可以在队列中使用 peek 方法。

public class PeekBufferedReader extends BufferedReader

    private Queue<String>       buf;
    private int                 bufSize;

    public PeekBufferedReader(Reader reader, int bufSize) throws IOException 
        super(reader);
        this.bufSize = bufSize;
        buf = Queues.newArrayBlockingQueue(bufSize);
    

    /**
     * readAheadLimit is set to 1048576. Line which has length over readAheadLimit 
     * will cause IOException.
     * @throws IOException 
     **/
    //public String peekLine() throws IOException 
    //  super.mark(1048576);
    //  String peekedLine = super.readLine();
    //  super.reset();
    //  return peekedLine;
    //

    /**
     * This method can be implemented by mark and reset methods. But performance of 
     * this implementation is better ( about 2times) than using mark and reset  
     **/
    public String peekLine() throws IOException 
        if (buf.isEmpty()) 
            while (buf.size() < bufSize) 
                String readLine = super.readLine();
                if (readLine == null) 
                    break;
                 else 
                    buf.add(readLine);
                
            
         else 
            return buf.peek();
        
        if (buf.isEmpty()) 
            return null;
         else 
            return buf.peek();
        
    

    public String readLine() throws IOException 
        if (buf.isEmpty()) 
            while (buf.size() < bufSize) 
                String readLine = super.readLine();
                if (readLine == null) 
                    break;
                 else 
                    buf.add(readLine);
                
            
         else 
            return buf.poll();
        
        if (buf.isEmpty()) 
            return null;
         else 
            return buf.poll();
        
    
    public boolean isEmpty() throws IOException 
        if (buf.isEmpty()) 
            while (buf.size() < bufSize) 
                String readLine = super.readLine();
                if (readLine == null) 
                    break;
                 else 
                    buf.add(readLine);
                
            
         else 
            return false;
        
        if (buf.isEmpty()) 
            return true;
         else 
            return false;
        
    

【讨论】:

您的解决方案背后的想法非常聪明,但我认为我们不需要扩展 BufferStreamReader 而是使用队列并将字节放入其中,同时查看数据包的大小或进行处理与您的协议有关。这将是一种拥有自己的缓冲区:)

以上是关于我可以偷看 BufferedReader 吗?的主要内容,如果未能解决你的问题,请参考以下文章

BufferedReader可以在Java中自动关闭吗

电子邮件会被盗吗?

偷看()或不偷看()

得到细胞索引 - 偷看和流行

bufferedreader 和 filereader 的具体区别

媳妇居然在家偷偷背着我偷看我的面试笔记,一个月后拿下大厂offer!