通过管道写入 FILE*

Writing FILE* through pipe

我在两个不同的进程中打开了两个文件。两者之间有管道相连。是否可以直接从一个文件写入另一个文件?特别是如果进程读取不知道它正在尝试读取的文件的大小?

我希望做这样的事情

#define length 100
int main(){
  int frk = fork();
  int pip[2];
  pipe(pip);
  if (frk==0){ //child
    FILE* fp fopen("file1", "r");
    write(pip[1],fp,length);
  }
  else {
    FILE* fp fopen("file2", "w");
    read(pip[0],fp,length);
}

Is it possible to write directly from one file to another?

C 没有为此提供任何机制,而且它似乎需要专门的硬件支持。标准 I/O 范例是数据从源读取到内存或从内存写入目标。中间那个讨厌的 "memory" 意味着不能直接从一个文件复制到另一个文件。

当然,您可以编写执行此类复制的函数或程序,对您隐藏详细信息。毕竟,这就是 cp 命令的作用,但 C 标准库不包含用于该目的的函数。

Especially if the process reading doesn't know the size of the file it's trying to read?

那一点不是很重要。一个人只是简单地阅读然后写(只)已经读过的东西,重复直到没有什么可读的了。 "Nothing more to read" 表示读取尝试通过其 return 值表明已到达文件末尾。

如果您希望一个进程读取一个文件而另一个进程将该数据写入另一个文件,使用管道在两者之间传输数据,那么您需要两个进程来实现该模式。一个从源文件读取并写入管道,另一个从管道读取并写入目标文件。

特别说明:对于从管道读取的进程检测该管道上的EOF,另一端必须关闭,在两个进程中。在 fork 之后,每个进程都可以而且应该关闭它不打算使用的管道端。使用写入端的那个然后在没有更多内容可写入时关闭该端。

在其他 unix 系统中,比如 BSD,有一个直接连接两个文件描述符的调用来做你想做的事情,但不知道 linux 中是否有一个系统调用可以做到这一点。无论如何,这不能用 FILE * 描述符来完成,因为这些是 <stdio.h> 库用来表示文件的缓冲文件 的 实例。您可以通过调用 getfd(3) 函数调用来获取 FILE * 实例的文件描述符(如系统所知)。

您试图从系统中获得的语​​义非常复杂,因为您希望某些东西将数据从一个文件描述符直接传递到另一个文件描述符,而无需任何进程(直接在内核中)的干预,并且内核需要一个线程池来完成直接从读取调用复制到写入调用的工作。

执行此操作的旧方法是创建一个线程,该线程负责从一个文件描述符(而不是 FILE * 指针)读取并写入另一个文件描述符。

另一件要评论的事情是 pipe(2) 系统调用给你两个 connected 描述符,允许你 read(2) 在一个( 0 索引)第二个(1 索引)中的 write(2)n 是什么。如果你 fork(2) 第二个进程,并且对两个进程都进行 pipe(2) 调用,你将有两个管道(每个管道有两个描述符),每个进程一个,它们之间没有关系。您将只能将每个进程与其自身进行通信,而不能与另一个进程(对其他进程的管道描述符一无所知)进行通信,因此它们之间将无法进行通信。

接下来是您尝试执行的操作的完整示例:

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#define length 100

#define FMT(fmt) "pid=%d:"__FILE__":%d:%s: " fmt, getpid(), __LINE__, __func__
#define ERR(fmt, ...) do {                  \
             fprintf(stderr,                     \
                     FMT(fmt ": %s (errno = %d)\n"), \
                     ##__VA_ARGS__,                  \
                     strerror(errno), errno);        \
             exit(1);                            \
        } while(0)

void copy(int fdi, int fdo)
{
    unsigned char buffer[length];
    ssize_t res, nread;

    while((nread = res = read(fdi, buffer, sizeof buffer)) > 0) {
        res = write(fdo, buffer, nread);
        if (res < 0) ERR("write");
    } /* while */
    if (res < 0) ERR("read");
} /* copy */

int main()
{
    int pip[2];
    int res;

    res = pipe(pip);
    if (res < 0) ERR("pipe");

    char *filename;

    switch (res = fork()) {
    case -1: /* error */
         ERR("fork");

    case 0:  /* child */
         filename = "file1";
         res = open(filename, O_RDONLY);
         if (res < 0) ERR("open \"%s\"", filename);
         close(pip[0]);
         copy(res, pip[1]);
         break;

    default: /* parent, we got the child's pid in res */
         filename = "file2";
         res = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0666);
         if (res < 0) ERR("open \"%s\"", filename);
         close(pip[1]);
         copy(pip[0], res);
         int status;
         res = wait(&status); /* wait for the child to finish */
         if (res < 0) ERR("wait");
         fprintf(stderr,
                 FMT("The child %d finished with exit code %d\n"),
                 res,
                 status);
         break;
    } /* switch */
    exit(0);
} /* main */