有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用ProcessBuilder使用交互式IO运行java C程序

<>我开发了一个ID/C++软件,使用^ {CD1>}(虽然有很多可用的,但我想要我自己的),可以编译和执行C或C++程序。因此,我尝试了一个简单的程序,使用ProcessProcessBuilder.在java中编译和执行C程序

下面是我的简单java程序,它编译并执行C程序:

public class RunProgram {

    public static void main(String[] args) throws Exception {
        new ProcessBuilder("gcc", "-o", "first", "first.c").start().waitFor(); //To Compile the source file using gcc and wait for compilation


/*
    Although I've to handle error-stream but 
for now, my assumption is that there is no error 
in program.
*/


        ProcessBuilder run = new ProcessBuilder("./first");

        execute.redirectErrorStream(true);

        Process runProcess = run.start();

        StreamReader sr = new StreamReader(runProcess.getInputStream());

        new Thread(sr).start(); //A new thread to handle output of program . 

    //rest of coding to provide input using OutputStream of 'runProcess' and to close the stream.

    }
}

class StreamReader implements Runnable {

    private InputStream reader;

   public StreamReader(InputStream inStream) {
      reader = inStream;

   }

   @Override
   public void run() {

      byte[] buf = new byte[1024];

        int size = 0;
        try {

            while ((size = reader.read(buf)) != -1) {

                System.out.println(new String(buf));
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
   }
}

这是我的first.c程序

#include<stdio.h>

int main() {
    int a;
    int k;

    printf("input a: ");

    scanf("%d", &a);
    for(k = 0; k < a; k++)
        printf("k = %d\n", k);
    return 0;
}

我想创建交互式IO控制台,就像大多数IDE或命令终端(Linux基本操作系统中的终端和基于Windows的操作系统中的命令提示符)一样。对于上面的例子:首先,它应该打印“Input a: “,然后等待提供输入,然后是程序的其余部分但它不会像我想的那样工作,因为它不会打印在scanf之前出现的printf语句的结果,直到我可能使用OutputStream提供输入

我在谷歌上搜索我的问题,访问了许多链接,但没有找到解决方案。同时,我发现了this链接,它建议在每个printf语句之后附加fflush,或者使用setbufsetvbuf方法(从一些其他子链接)清除缓冲区。但是一个新手(即将学习C)可能不知道fflush或这些函数,他/她永远不会使用它,因为它在其他IDE中不需要,甚至在终端上也不需要。 如何解决此问题并为我的IDE构建集成控制台

以下是我想要的东西的一瞥:

animation of Interactive IO


共 (2) 个答案

  1. # 1 楼答案

    从上面的评论中可以看出,在这里添加一点关于I/O流缓冲工作原理的解释是有意义的

    当调用printf(3)之类的函数时,在幕后发生的事情是,数据被写入缓冲区,直到缓冲区填满或发生某种触发。 然后将缓冲区的内容从缓冲区复制到实际输出设备/另一个输出缓冲区。。。 触发器通常遇到行结束(\n在Linux/Unix下)。 因此,这种缓冲的粗略版本是:

    struct buffered_file_t {
    
        char* buffer;
        size_t capacity;
        size_t current_char;
        FILE* file;
    
    };
    
    void flush_buffered(struct buffered_file_t* file) {
    
        assert(0 != file);
        assert(0 != file->buffer);
    
        fwrite(file->buffer, file->current_char, 1, file->file);
        file->current_char = 0;
    
    }
    
    
    void print(struct buffered_file_t* file, const char* str) {
    
        assert(0 != file);
        assert(0 != file->buffer);
        assert(0 != str);
    
        for(size_t i = 0;  0 != str[i]; ++i) {
    
            if(file->current_char >= file->capacity - 1) flush_buffered(file);
            file->buffer[file->current_char++] = str[i];
            if('\n' == str[i]) flush_buffered(file);
    
        }
    
    }
    

    现在,如果调用print

    const size_t BUFSIZE = 100;
    
    struct buffered_file_t stdout_buffered = {
        .buffer = calloc(1, BUFSIZE),
        .capacity = BUFSIZE,
        .current_char = 0,
        .file= stdout,
    };
    
    print(&stdout_buffered, "Naglfar\n");
    print(&stdout_buffered, "Surthur");
    

    你永远不会看到Surthur出现在stdout上。 为了将它从缓冲区写入stdout,您必须

    • 显式调用flush_buffered
    • 通过减少缓冲区大小(buffered_file.capacity = 1在上面的示例中)禁用缓冲

    在您的情况下,您不能显式地调用fflush(3)(这就是您所说的需求)。因此,剩下的唯一方法就是禁用缓冲

    如何做到这一点取决于操作系统,IMHO。 对于Linux,请查看Coreutils包中的stdbuf(1),了解如何为某些外部进程流禁用缓冲

  2. # 2 楼答案

    在GNU/Linux下,要关闭标准I/O流的缓冲,可以使用^{}如下所示:

     ....
     ProcessBuilder run = new ProcessBuilder("stdbuf", "-o0", "./first");
     ....
    

    如果要关闭stderrstdin的缓冲,请添加-e0-i0选项

    当然,如果您不必依赖外部工具,而是可以在您自己的代码中关闭缓冲,那就更好了-最简单的事情是看一下stdbuf的源代码,但我想最终您将不得不使用JNI,然后,我想,我只会坚持stdbuf