首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >和OutputStream操作

和OutputStream操作
EN

Stack Overflow用户
提问于 2015-06-17 08:26:46
回答 4查看 1.2K关注 0票数 2

我有slcanterm.exe命令行实用工具,用我的USB-CAN适配器执行终端功能,连接到PC.我需要从Java应用程序启动这个实用程序,然后在循环中对这个终端进行读写。我的问题是我不能让InputStream和OutputStream一起工作:

代码语言:javascript
复制
System.out.println( "hello" );
String line;
OutputStream stdin = null;
InputStream stderr = null;
InputStream stdout = null;

Process process = Runtime.getRuntime ().exec ("cmd.exe");
stdin = process.getOutputStream ();
stderr = process.getErrorStream ();
stdout = process.getInputStream ();

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
BufferedReader reader = new BufferedReader (new InputStreamReader (stdout));

line = "slcanterm.exe" + "\n";
writer.write(line );
writer.flush();

// If I uncomment this line reader.readLine() loop is stucked
//writer.close();

while ((line = reader.readLine ()) != null)     
    System.out.println ("[Stdout] " + line);

System.out.println( "buy" );

如果我不关闭writer流,while ((line = reader.readLine ()) != null)就会被塞住。我需要执行reader.readLine ()writer.write(line )在循环中的工作。有什么解决办法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-06-17 09:17:05

代码语言:javascript
复制
    System.out.println( "hello" );
    String line;

    Process process = Runtime.getRuntime ().exec ("cmd.exe /c slcanterm.exe");

    InputStream stderr = process.getErrorStream ();
    InputStream stdout = process.getInputStream ();

    BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
    BufferedReader error = new BufferedReader (new InputStreamReader(stderr));

    new Thread() {
        public void run() {
            try {
                String err;
                while ((err = error.readLine ()) != null)     
                    System.out.println ("[Stderr] " + err);
            } catch (Exception e) {
                e.printStackTrace();
            }

    }}.start();

    while ((line = reader.readLine ()) != null)     
        System.out.println ("[Stdout] " + line);

    System.out.println( "buy" );
票数 0
EN

Stack Overflow用户

发布于 2015-06-17 08:44:12

1)您的代码(基本上)是正确的。但是,我遇到了一个类似的问题,另一个进程在关闭它的输入流时没有很好的响应。如果关闭进程的输入流(编写器),则流程实际上会看到他的输入流已关闭,并在试图从中读取时失败。在我的例子中,当他的阅读失败时,我开始的过程没有得到很好的响应。这似乎也是同样的问题。

2)您可以通过直接启动slcanterm.exe而不使用cmd.exe来规避这一切。

3)我看到的另一种可能性是,您只添加"\n",也许cmd.exe需要"\n\r“。

票数 1
EN

Stack Overflow用户

发布于 2015-06-17 08:47:09

输出流将保持打开状态,直到进程退出为止。当进程决定终止时退出,它将显式终止,或者通过关闭输入流隐式地终止,例如。

这意味着您的readLine将被阻塞,直到cmd.exe有更多的输出,但是,由于您没有发送更多的命令,所以没有任何命令。永远也不会是。

在简单的情况下,您可以关闭输入或写入exit命令来关闭控制台。如果slcanterm.exe是您想要运行的唯一程序,那么您可以直接启动该进程。如果您想要运行更多的命令,那么您需要一种方法来检测错误(不要忽略错误流)或检测命令的输出已经终止。如果运行的命令没有一致的最后一行,那么可以将echo ---MARKER---写入stdin并检测该行何时出现(这意味着最后一个命令已经终止,echo已被执行)。

很多可能性。这取决于你想做什么。

下面的课演示了我所建议的简单技巧。另外,它确保了echo off,并且忽略了所有不是命令输出的内容(因为cmd.exe输出每个输入字符)。

代码语言:javascript
复制
class CommandRunner implements Closeable {

    private Process cmd;
    private OutputStreamWriter stdin;
    private BufferedReader stderr;
    private BufferedReader stdout;

    private static class ArtificialOutput {
        public List<String> inputLines;
        public String finalMarker;

        public ArtificialOutput(List<String> inputLines, String finalMarker) {
            super();
            this.inputLines = inputLines;
            this.finalMarker = finalMarker;
        }
    }

    public CommandRunner() throws IOException {
        cmd = Runtime.getRuntime().exec("cmd.exe");
        stdin = new OutputStreamWriter(cmd.getOutputStream());
        stderr = new BufferedReader(new InputStreamReader(cmd.getErrorStream()));
        stdout = new BufferedReader(new InputStreamReader(cmd.getInputStream()));   

        // turn off echo of commands (also skips any console header lines)
        execute("echo off", StdinWriter.WRITE_NOTHING, StdoutProcessor.IGNORE);
    }

    @Override
    public void close() throws IOException {
        stdin.close();
        stdout.close();
        stderr.close();
        cmd.destroy();
    }

    public void execute(String command, StdinWriter writer, StdoutProcessor processor) throws IOException {             
        processOutput(executeCommand(command, writer), processor);
    }

    private ArtificialOutput executeCommand(String command, StdinWriter writer) throws IOException {
        List<String> lines = new ArrayList<String>();

        // add command as input line
        lines.add(command);

        // add all custom input lines
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        try (OutputStreamWriter bufferWriter = new OutputStreamWriter(buffer)) {
            writer.write(bufferWriter);
        }

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buffer.toByteArray())))) {
            String line = null;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        }

        // add stdout and sterr markers as input lines
        String marker = "--- MARKER " + System.currentTimeMillis() + Math.random();
        lines.add("echo " + marker + ">&2");
        lines.add("echo " + marker);

        // write everything to stdin
        for (String line : lines) {
            stdin.write(line + System.lineSeparator());
        }
        stdin.flush();

        // our artificial outputs (with echo off) are the input lines and the closing marker
        return new ArtificialOutput(lines, marker);
    }

    private void processOutput(ArtificialOutput artificialOutput, StdoutProcessor processor) throws IOException {
        byte[] output = readUntilMarker(artificialOutput, stdout);
        byte[] errors = readUntilMarker(artificialOutput, stderr);

        if (errors.length > 0) {
            processor.processError(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(errors))));
        }

        processor.processOuput(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(output))));
    }

    private byte[] readUntilMarker(ArtificialOutput artificialOutput, BufferedReader reader) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(buffer))) {;
            String line;
            while ((line = reader.readLine()) != null) {
                // ignore input lines because cmd.exe outputs every input character
                if (artificialOutput.inputLines.remove(line)) {
                    continue;
                }

                // the final marker indicates the command has ended
                if (line.equals(artificialOutput.finalMarker)) {
                    break;
                }

                // everything else is the command output
                writer.write(line + System.lineSeparator());
            }
        }

        return buffer.toByteArray();
    }

}

有了这个类,您可以在程序中这样做:

代码语言:javascript
复制
try (CommandRunner cmd = new CommandRunner()) {
    cmd.execute("dir", StdinWriter.WRITE_NOTHING, StdoutProcessor.PRINT);
    cmd.execute("echo something", StdinWriter.WRITE_NOTHING, StdoutProcessor.PRINT);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30886148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档