1

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

我希望做这样的事情

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

2 回答 2

3

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

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

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

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

那一点不是很重要。一个人简单地读然后写(只)他读过的东西,重复直到没有更多的东西要读。“Nothing more to read”意味着读取尝试通过其返回值表明已到达文件末尾。

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

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

于 2017-11-15T17:24:05.003 回答
1

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

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

这样做的旧方法是创建一个线程,该线程从一个文件描述符(而不是FILE *指针)读取并写入另一个文件描述符。

要评论的另一件事是,pipe(2)系统调用为您提供了两个连接的描述符,允许您read(2)在一个(索引)中的第二个(索引)中的 n 是0什么。如果您是第二个进程,并且您对这两个进程都进行了调用,那么您将有两个管道(每个都有两个描述符),每个进程中都有一个,它们之间没有任何关系。您将只能与每个进程与其自身进行通信,但不能与另一个进程(它对其他进程的管道描述符一无所知),因此它们之间将无法进行通信。write(2)1fork(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 */
于 2017-11-16T10:59:00.940 回答