通过管道写入文件*

时间:2017-11-15 16:40:52

标签: c pipe fork file-pointer

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

我希望做这样的事情

#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);
}

2 个答案:

答案 0 :(得分:3)

  

是否可以直接从一个文件写入另一个文件?

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

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

  

特别是如果进程读取不知道它试图读取的文件的大小?

这一点不是很重要。一个人简单地读取然后写入(仅)一个人读过的东西,重复直到没有其他东西可读。 “无需阅读”意味着读取尝试通过其返回值指示已到达文件末尾。

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

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

答案 1 :(得分:1)

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

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

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

要评论的另一件事是pipe(2)系统调用为您提供了两个连接的描述符,允许您在一个read(2)索引中0第二个(write(2)索引)中的1 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 */
相关问题