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

时间:2018-05-18 06:22:29

标签: java process io processbuilder

我正在使用public class WebViewActivity extends AppCompatActivity { public static final int DOWNLOAD_REQUEST_CODE= 1024; @Override protected void onCreate(final Bundle savedInstanceState) { ... webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.endsWith(".jpg")) { int check = ActivityCompat.checkSelfPermission(this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE); if (check == PackageManager.PERMISSION_GRANTED) { //DO the download stuff here } else { requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},DOWNLOAD_REQUEST_CODE); } } } }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if(requestCode == DOWNLOAD_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED){ //DO the download stuff here } } } 开发一种用于C / C ++的IDE软件(虽然有很多可用的,但我想要自己的),可以编译和执行C或C ++程序。所以我尝试了一个简单的程序,使用javaProcess

在java中编译和执行C程序

这是我编写和执行C程序的简单java程序:

ProcessBuilder.

这是我的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; } 控制台,就像大多数IDE或命令终端一样(基于Linux的终端操作系统和基于Windows的操作系统中的命令提示符)。对于上面的示例:首先,它应该打印IO,然后等待提供输入然后继续提供程序。但它不会像我想象的那样工作,因为它在我“Input a: “之前提供输入之前,我不会打印printf语句的结果。

我搜索了我的问题并访问了许多链接,但没有得到解决方案。同时,我发现this链接建议在每个scanf语句后添加OutputStream或使用fflushprintf方法(来自其他一些子链接)清除缓冲区。但是一个新人(将要学习C)可能不会意识到setbuf或这些功能,他/她将永远不会使用它,因为它在其他IDE中甚至在终端上都不需要。 如何解决此问题并为IDE构建集成控制台

以下是我想要的一瞥:

animation of Interactive IO

2 个答案:

答案 0 :(得分:2)

从上面的评论中,考虑添加一些关于I / O流缓冲如何工作的解释在这里是有道理的。

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

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)(这是您所说的要求)。因此,剩下的唯一手段是禁用缓冲。

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

答案 1 :(得分:0)

在GNU / Linux下,为了关闭标准I / O流的缓冲,您可以使用stdbuf(1),如下所示:

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

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

当然,如果您不必依赖外部工具但可以在自己的代码中关闭缓冲会更好 - 最简单的事情是查看stdbuf的来源,但是我猜猜最终你必须使用JNI,然后,我想,我会坚持stdbuf ......