即使已读取一行,BufferedReader#readLine() 也会挂起

BufferedReader#readLine() hangs even though a line has been read

更新问题(更清楚):

有没有办法设计下面的InputStream,使得BufferedReader#readLine()读取换行符后会return?

在下面的示例中,即使 reader 读取了新行,readLine() 也会永远挂起,因为(大概)它正在等待缓冲区填满。理想情况下,readLine() 会在读取换行符后 return。

我知道我想要的东西是可能的,因为当您使用 BufferedReader#readLine()System.in 读取时,它不会在 returning 之前等待缓冲区填满。

import java.io.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Example {

    private static final class MyInputStream extends InputStream {

        public final BlockingQueue<String> lines = new LinkedBlockingQueue<>();
        private InputStream current = null;

        @Override
        public int read() throws IOException {
            try {
                if(current == null || current.available() == 0)
                    current = new ByteArrayInputStream(lines.take().getBytes("UTF-8"));
                return current.read();
            }
            catch(InterruptedException ex) {
                return -1;
            }
        }       
    }

    public static void main(String[] args) throws Exception {
        MyInputStream myin = new MyInputStream();
        myin.lines.offer("a line\n");
        BufferedReader in = new BufferedReader(new InputStreamReader(myin));
        System.out.println(in.readLine());
    }
}

此外,如果有更好的方法将字符串发送到 InputStream,我愿意接受建议。

接受的解决方案:

根据 Sotirios Delimanolis 在其解决方案的评论之一中提出的建议,我将改为使用 PipedInputStream。只要在发送包含换行符的字符串后调用 PipedOutputStream#flush(),我就会立即将它耦合到 PipedOutputStreamBufferedReader#readLine() returns。

Also, if there is a better way to send a string to an InputStream, I'm open to suggestions.

好吧,您可以尝试使用 BufferedReader 而不是 InputStream,看起来像这样:

public int read(String directory) throws Exception{
    String line = "";
    File file = new File(directory);
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);

    do{
        lines.add(br.readLine());
    while(br.readLine() != null);

    br.close();

    return Integer.parseInt(line);
}

更新问题后,让 BufferedReader 在换行符后停止读取的唯一方法是将缓冲区大小设置为 1,这完全不需要 BufferedReader

您必须编写自己的实现。


A BufferedReader 读取的字节数超过要求。在您的情况下,这意味着它将比换行符读得更远。例如,对于 Oracle JVM,它将尝试读取 8192 字节。通过您的继承层次结构,这

System.out.println(in.readLine());

将尝试调用您的 read() 方法 8192 次。

前 6 次调用将 return 一个值,一个值对应 String 字节数组中的每个字符。下一篇,见

if(current == null || current.available() == 0)
     current = new ByteArrayInputStream(lines.take().getBytes("UTF-8"));

current.available() 将 return 0 因为 ByteArrayInputStream 已完全消耗。然后它将尝试从 BlockingQueuetake 并无限期地阻止。