我的任务是从文本文件中获取一些数据,解析单词,按字母顺序排序,删除重复项,然后将它们输出到新的文本文件。这是使用三个过程完成的,使用IPC管道。这是我第一次使用管道或任何IPC工作,所以如果我有点不熟悉,请理解。
所以我将main函数分为三个进程:input / parent,sort(child)和output(grandchild)。我在父进程中创建了一个IO流,需要将它传递给sort proc。我创建了该管道并关闭了未使用的末尾(stdin
用于输入,stdout
用于排序。)
我的问题是:我不知道如何将数据从IO缓冲区移动到管道中(在stdout处)。我觉得它应该使用fputs
,其中解析的单词列表一次只能传递给stdout
一个单词。
以下是我为输入过程创建的内容。文件IO不是我的强项,所以如果有错误,请告诉我,我会尽我所能解决它们。谢谢你的帮助!
} else { /* This is the input/parent process */
printf("This is the input process\n");
close(input_to_sortFD[0]); /*
* Closes the parent-side read-end of
* the pipe
*/
pipeStream = fdopen(input_to_sortFD[1], "w"); /*
* Buffer that feeds into
* write-end of pipe
*/
ioFileFD = fopen(ioFile, "r");
if (ioFileFD == NULL) {
perror("Fatal error: failed to open requested file");
exit(-1);
}
int i = 0;
while (fscanf(ioFileFD, "%s", wordList) != EOF) {
fputs(wordList[i], stdout);
i++;
}
}
答案 0 :(得分:2)
您的问题是:
我不知道如何将数据从IO缓冲区移动到管道中(在stdout处)。
从我收集的内容来看,你过度思考问题。如果您知道如何从FILE *
读取并写入FILE *
,那么管道没有什么特别之处。
我会像这样构建程序:
您可以分别使用sed
和sort
对“wordify”和“sortunique”流程进行原型设计。下面的原型将单词定义为连续出现的字母字符。
void wordify (FILE *infile, FILE *outfile)
{
int r;
make_stdio(infile, outfile);
r = execlp("sed", "sed", "-e",
"s/[^a-zA-Z][^a-zA-Z]*/ /g;s/^ *//;s/ *$//;/^$/d;s/ /\\n/g",
(char *)0);
assert(r == 0);
}
void sortunique (FILE *infile, FILE *outfile)
{
int r;
make_stdio(infile, outfile);
r = execlp("sort", "sort", "-u", (char *)0);
assert(r == 0);
}
由于原型使用execlp()
,因此infile
需要映射到stdin
,而outfile
需要映射到stdout
。这是通过dup2()
完成的,但我实现了一个处理fdup2()
的包装函数FILE *
。
FILE * fdup2 (FILE *oldstream, FILE *newstream)
{
if (newstream) {
if (fileno(oldstream) != fileno(newstream)) {
if (dup2(fileno(oldstream), fileno(newstream)) < 0) return 0;
fclose(oldstream);
}
return newstream;
}
return oldstream;
}
void make_stdio (FILE *infile, FILE *outfile)
{
FILE *x = fdup2(infile, stdin);
FILE *y = fdup2(outfile, stdout);
assert(x && y);
}
按预期使用fork()
启动流程。
void launch (void (*func)(FILE *, FILE *), FILE *infile, FILE *outfile)
{
assert(infile && outfile);
switch (fork()) {
case -1: perror("fork");
exit(EXIT_FAILURE);
case 0: func(infile, outfile);
exit(EXIT_SUCCESS);
default: fclose(infile);
fclose(outfile);
}
}
现在,主程序只需要打开输入和输出文件,创建管道,启动进程,然后等待它们完成。唯一的技巧是必须使用管道,以便它的写入结束是wordify
的输出,并且它的读取结束是sortunique
的输入。
int main (int argc, char *argv[])
{
FILE *infile;
FILE *outfile;
int pipefds[2];
int r;
if (argc < 3) {
fprintf(stderr, "need input and output filenames\n");
exit(EXIT_FAILURE);
}
if ((infile = fopen(argv[1], "r")) == 0) {
perror(argv[1]);
exit(EXIT_FAILURE);
}
if ((outfile = fopen(argv[2], "w")) == 0) {
perror(argv[2]);
exit(EXIT_FAILURE);
}
r = pipe(pipefds);
assert(r == 0);
launch(wordify, infile, fdopen(pipefds[1], "w"));
launch(sortunique, fdopen(pipefds[0], "r"), outfile);
while (waitpid(-1, 0, 0) == 0) {}
return 0;
}
注意,共有3个进程参与。如果您必须启动3,并且有4个流程参与,我会考虑将sortunique
拆分为sort
和unique
。
r = pipe(pipefds1);
assert(r == 0);
r = pipe(pipefds2);
assert(r == 0);
launch(wordify, infile, fdopen(pipefds1[1], "w"));
/* sort: behaves like "sort" command with no arguments */
launch(sort, fdopen(pipefds1[0], "r"), fdopen(pipefds2[1], "w"));
/* unique: behaves like "uniq" command with no arguments */
launch(unique, fdopen(pipefds2[0], "r"), outfile);
while (waitpid(-1, 0, 0) == 0) {}
一旦将问题分解为这些组件,那么实现特定组件只是标准的读取输入和编写输出练习。管道问题被抽象掉,因为文件流按正确的顺序排列,组件只是读写。您甚至可以删除make_stdio()
代码,然后阅读infile
并写信至outfile
。
答案 1 :(得分:0)
通常,管道通信是通过read()和write()调用完成的。但是我看到你正在将int文件描述符提升为FILE *,以便你可以使用fscanf和朋友。
如果您使用fscanf()进行阅读,可以使用fprintf()进行书写。