Java System.in和自定义InputStreamReader之间的行为差异

Java System.in和自定义InputStreamReader之间的行为差异,java,polymorphism,inputstream,bufferedreader,Java,Polymorphism,Inputstream,Bufferedreader,我编写了一个JavaCLI程序,从stdin中读取行,并为每行输出一个可能的补全。我正在尝试为它提供一个gui,因此我正在尝试为System.in构建一个插件,以允许用户使用gui或cli 到目前为止,我得到了这个替换,当在JTextArea中输入文本时,将调用其方法add: import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStre

我编写了一个JavaCLI程序,从stdin中读取行,并为每行输出一个可能的补全。我正在尝试为它提供一个gui,因此我正在尝试为
System.in
构建一个插件,以允许用户使用gui或cli

到目前为止,我得到了这个替换,当在JTextArea中输入文本时,将调用其方法
add

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class GuiIn extends InputStream {

    protected LinkedBlockingQueue<Byte> buf;
    protected boolean closed;

    public GuiIn() {
        closed = false;
        buf = new LinkedBlockingQueue<Byte>();
    }

    @Override
    public void close() {
        closed = true;
    }

    /**
     * add strings to read in the InputStream. Arguments are ignored if the
     * stream is closed.
     * 
     * @param s
     *            a string. Ignored if null
     */
    public void add(String s) {
        if (closed || s == null) {
            return;
        }
        byte[] bs = s.getBytes();
        LinkedList<Byte> lbs = new LinkedList<Byte>();
        for (byte b : bs) {
            lbs.add(b);
        }
        buf.addAll(lbs);
    }

    @Override
    public int available() {
        return buf.size();
    }

    @Override
    public synchronized int read() throws InterruptedIOException {
        if (closed && buf.isEmpty()) {
            return -1;
        }
        Byte b = 0;

        while (true) {
            try {

                if ((b = buf.poll(100, TimeUnit.MILLISECONDS)) == null) {
                    if (closed && buf.isEmpty())
                        return -1;
                } else
                    break;

            } catch (InterruptedException e) { 
                throw new InterruptedIOException("interrupted: "
                        + e.getMessage());
            }
        }
        return b;
    }
}
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
导入java.io.InterruptedIOException;
导入java.util.LinkedList;
导入java.util.concurrent.LinkedBlockingQueue;
导入java.util.concurrent.TimeUnit;
公共类GUI扩展了InputStream{
受保护的LinkedBlockingQueue buf;
受保护布尔闭合;
公共语言{
关闭=错误;
buf=新的LinkedBlockingQueue();
}
@凌驾
公众假期结束(){
关闭=真;
}
/**
*添加要在InputStream中读取的字符串。如果
*溪流关闭了。
* 
*@param s
*字符串。如果为null,则忽略
*/
公共无效添加(字符串s){
if(闭合| | s==null){
返回;
}
字节[]bs=s.getBytes();
LinkedList lbs=新建LinkedList();
for(字节b:bs){
lbs.add(b);
}
总重量(磅);
}
@凌驾
公共int可用(){
返回buf.size();
}
@凌驾
public synchronized int read()引发InterruptedIOException{
if(已关闭&&buf.isEmpty()){
返回-1;
}
字节b=0;
while(true){
试一试{
if((b=buf.poll(100,时间单位毫秒))==null){
if(已关闭&&buf.isEmpty())
返回-1;
}否则
打破
}捕获(中断异常e){
抛出新的InterruptedIOException(“interrupted:
+e.getMessage());
}
}
返回b;
}
}
然而,当我用
newbufferedreader(newinputstreamreader(in))试用它时
并尝试
readLine()
it,它似乎会阻塞,直到有足够的字符(很多),尽管我的侦听器总是在输入的文本后面加上新行

另一方面,如果中的
设置为
系统。在
中,每一行在输入后立即读取

因此,我的问题分为两部分:

  • 这种差异从何而来
  • 如何修复它
  • 请注意,从裸
    GuiIn
    中读取每个字节是正确的,我已经尝试过一些技巧,比如减小
    BufferedReader
    的缓冲区大小


    我还提前搜索了web:这不是关于创建模拟对象;而且也不是一个选项:它不支持追加。

    问题的一个根源可能是,
    InputStreamReader
    可能会坚持阅读更远的内容,这样它就可以确定它使用的
    字节
    ->
    char
    解码器(对它来说是不透明的)有足够的字节来生成完整的
    字符,而
    系统。in
    可能对默认编码有足够的了解,以提供足够的字节

    在开始使用Java进行交互式控制台操作之前,您应该熟悉类和端口

    然后,我将在更高级别上进行抽象,而不是在不指定编码的情况下创建
    InputStreamReader
    s:

    interface CommandLineSource {
      String readLine() throws IOException;
    }
    

    然后,您可以创建一个由
    FileDescriptor.STDIN
    支持的,另一个由您喜欢的任何东西支持的,这样您就可以自动进行测试输入。

    围绕这个问题进行抽象是一个好主意,尽管在多态性方面有点失望。使用控制台似乎不合适,因为文档不能保证重定向流时控制台的存在(我打算执行批处理以分析许多完成情况)。有一件事:这与测试无关:我已经有JUnit类直接和完成类交互。无论如何,谢谢你的指点@伯纳德·保卢斯,是的。这是一件令人失望的事。我知道默认的
    System.out
    做了很多操作系统特有的废话,试图同时充当字节和字符接收器,我怀疑
    System.in
    类似。如果您进行了抽象,那么您可以在可用的地方使用
    控制台
    ,但当
    System.Console()==null
    时,您可以回到缓冲读取器周围的简单包装器。事实上,是解码器导致了问题:openjdk-6的行为方式与官方sdk(java 6)相同通过查看openjdk的源代码可以证实这一点。没有完全通过确切的解码器类,但那是另一次。再次感谢!