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

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

【问题讨论】:

  • 我感觉 C++ 的窥视和 Java 的窥视有歧义。 “检查是否有要读的东西”与 Java 中的“peek”不匹配。

标签: java bufferedreader 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 而是使用队列并将字节放入其中,同时查看数据包的大小或进行处理与您的协议有关。这将是一种拥有自己的缓冲区:)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-08
          • 2018-06-19
          • 2013-04-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多