即使已读取一行,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()
,我就会立即将它耦合到 PipedOutputStream
和 BufferedReader#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
已完全消耗。然后它将尝试从 BlockingQueue
到 take
并无限期地阻止。
更新问题(更清楚):
有没有办法设计下面的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()
,我就会立即将它耦合到 PipedOutputStream
和 BufferedReader#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
已完全消耗。然后它将尝试从 BlockingQueue
到 take
并无限期地阻止。