我实现了一个带有GTK3的GUI,它基本上为exe程序生成一个输入文本文件,这些输入可以进行详细说明。 通过系统调用(系统(" exe input.dat&"))将此exe放入GUI中执行。
此exe可以在屏幕上打印信息或错误消息。
我想要做的是在GtkTextView上重定向这些消息。
我的想法是将输出和错误重定向到文件(系统(" exe input.dat> output_file.txt 2>& 1&"))和GUI中逐行阅读 文件并在textView中发送此字符串。
我不确定2个进程是否可以写入和读取同一个文件并测试这个概念我使用了这2个简单的程序: 作者(像./writer> out_file.txt一样使用):
#include <stdio.h>
#include <unistd.h>
main()
{
int a;
while(1)
{
fprintf(stdout,"a=%d\n",a);
fflush(stdout);
sleep(1);
a++;
}
}
和读者:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
fp = fopen("out_file.txt","r");
char string_new[1024];
char string_old[1024];
strcpy(string_old," ");
while(1)
{
fgets(string_new,1024,fp);
if ( strlen(string_new) != 0 )
{
if ( strcmp(string_new, string_old) != 0 )
{
fprintf(stdout,"%s",string_new);
fflush(stdout);
strcpy(string_old,string_new);
}
}
}
}
这两个程序正确运行,第二个程序打印第一个程序的输出。
在GUI中添加类似的代码,GUI只读取文件的第一行。
我如何解决这个问题? 谢谢
答案 0 :(得分:1)
您应该使用popen
而不是执行system("exe input.dat &")
,然后从程序的stdout
输出中轻松阅读。
像这样:
#include <stdio.h>
int main(void)
{
FILE *fp = popen("ls -lah /tmp", "r");
if(fp == NULL)
return 1;
char buffer[1024];
int linecnt = 0;
while(fgets(buffer, sizeof buffer, fp))
printf("Line: %d: %s", ++linecnt, buffer);
putchar('\n');
fclose(fp);
return 0;
}
输出:
$ ./b
Line: 1: total 108K
Line: 2: drwxrwxrwt 8 root root 12K Mar 10 02:30 .
Line: 3: drwxr-xr-x 26 root root 4.0K Feb 15 01:05 ..
Line: 4: -rwxr-xr-x 1 shaoran shaoran 16K Mar 9 22:29 a
Line: 5: -rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
Line: 6: -rw------- 1 shaoran shaoran 16K Mar 9 22:29 .a.c.swp
Line: 7: -rwxr-xr-x 1 shaoran shaoran 11K Mar 10 02:30 b
Line: 8: -rw-r--r-- 1 shaoran shaoran 274 Mar 10 02:30 b.c
Line: 9: -rw------- 1 shaoran shaoran 12K Mar 10 02:30 .b.c.swp
Line: 10: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 firefox_shaoran
Line: 11: drwxrwxrwt 2 root root 4.0K Mar 9 20:06 .ICE-unix
Line: 12: srwx------ 1 mongodb mongodb 0 Mar 9 20:07 mongodb-27017.sock
Line: 13: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-c2s-1874
Line: 14: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-s2c-1874
Line: 15: drwxrwxr-x 2 root utmp 4.0K Mar 9 20:06 screen
Line: 16: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:07 ssh-XueH0w8zWCSE
Line: 17: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 thunderbird_shaoran
Line: 18: -r--r--r-- 1 root root 11 Mar 9 20:07 .X0-lock
Line: 19: drwxrwxrwt 2 root root 4.0K Mar 9 20:07 .X11-unix
如果您需要更多控制权并希望阅读stderr
,那么您必须为stdout
和stderr
创建管道,
将fork
和孩子dup2
的管道设为stderr
&amp; stdout
和
然后执行exec
(或该系列的任何其他功能)来执行
程序
像这样:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
int stdout_pipe[2];
int stderr_pipe[2];
pipe(stdout_pipe);
pipe(stderr_pipe);
pid_t pid = fork();
if(pid < 0)
return 1;
if(pid == 0)
{
// closing reading ends and duplicating writing ends
close(stdout_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
close(stderr_pipe[0]);
dup2(stderr_pipe[1], STDERR_FILENO);
execlp("ls", "ls", "-alh", "a.c", "kslkdl", NULL);
exit(1);
}
// closing writing end
close(stdout_pipe[1]);
close(stderr_pipe[1]);
int status;
if(waitpid(pid, &status, 0) < 0)
{
fprintf(stderr, "could not wait\n");
return 1;
}
if(WIFEXITED(status) == 0)
{
fprintf(stderr, "ls exited abnormally\n");
close(stdout_pipe[0]);
close(stderr_pipe[0]);
return 1;
}
puts("STDOUT:");
char buffer[1024];
ssize_t len;
while((len = read(stdout_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stdout_pipe[0]);
puts("STDERR:");
while((len = read(stderr_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stderr_pipe[0]);
return 0;
}
输出:
$ ./b
STDOUT:
-rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
STDERR:
ls: cannot access 'kslkdl': No such file or directory
答案 1 :(得分:1)
Pablo's answer是正确的,您需要使用pipe(7) - s。
你可以使用GTK&amp; Glib的g_spawn_async_with_pipes
(基于Linux上的pipe
和fork
以及execve
)(而不是fork
或popen
)。在GTK交互式程序中,它比通常的popen
更好,因为分叉程序将与事件循环同时运行。
您甚至可以考虑在使用g_source_add_unix_fd
调用的pipe(2)或g_spawn_async_with_pipes
给出的管道fd-s(或部分)上使用pipe(2)。但您可能更喜欢g_io_channel_unix_new
和g_io_add_watch
请注意,GTK主循环(和Gtk Input and Event Handling Model),即GtkApplication和相关的g_application_run
或较早的gtk_main
围绕某些event loop多路复用系统调用如poll(2)(或较旧的select(2)),您可能需要该循环来了解您的管道。当一些数据到达管道时,你可能想要read(2)它(然后调用一些GtkTextBuffer插入函数)。
您应该做出设计选择:您是否希望GUI界面和其他进程同时运行?或者另一个exe
进程是否总是如此快速且输出较小(并且没有输入),您可能只使用popen
?
在当前的GUI应用程序中,如果您需要响应式GUI应用程序,事件循环应该快速运行(每秒至少30或50次)。
还要查看某些现有free software GTK应用程序的源代码中的灵感(例如,在github或您的Linux发行版上)。