简体   繁体   English

通过管道写入FILE *

[英]Writing FILE* through pipe

I have two file open in two different processes. 我在两个不同的过程中打开了两个文件。 There's a pipe connecting the two. 有一条管道将两者连接。 Is it possible to write directly from one file to another? 是否可以直接从一个文件写入另一个文件? Especially if the process reading doesn't know the size of the file it's trying to read? 特别是如果进程读取不知道要读取的文件大小?

I was hoping to do something like this 我希望做这样的事情

#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 does not provide any mechanism for that, and it seems like it would require specialized hardware support. C没有为此提供任何机制,并且似乎需要专门的硬件支持。 The standard I/O paradigm is that data get read from their source into memory or written from memory to their destination. 标准的I / O范例是将数据从其源读取到内存或从内存写入到目的地。 That pesky "memory" in the middle means copying from one file to another cannot be direct. 中间那讨厌的“内存”意味着不能直接从一个文件复制到另一个文件。

Of course, you can write a function or program that performs such a copy, hiding the details from you. 当然,您可以编写执行此类复制的函数或程序,从而将详细信息隐藏起来。 This is what the cp command does, after all, but the C standard library does not contain a function for that purpose. 毕竟,这是cp命令执行的操作,但是C标准库不包含用于此目的的函数。

Especially if the process reading doesn't know the size of the file it's trying to read? 特别是如果进程读取不知道要读取的文件大小?

That bit isn't very important. 那不是很重要。 One simply reads and then writes (only) what one has read, repeating until there is nothing more to read. 一个人简单地读取然后写入(仅)一个已读取的内容,重复进行直到没有其他要读取的内容为止。 "Nothing more to read" means that a read attempt indicates by its return value that the end of the file has been reached. “没什么要读取的”表示读取尝试通过其返回值指示已到达文件末尾。

If you want one process to read one file and the other to write that data to another file, using a pipe to convey data between the two, then you need both processes to implement that pattern. 如果要一个进程读取一个文件,而另一个进程使用管道在两个文件之间传送数据,则另一个进程将该数据写入另一个文件,则需要两个进程来实现该模式。 One reads from the source file and writes to the pipe, and the other reads from the pipe and writes to the destination file. 一个从源文件读取并写入管道,另一个从管道读取并写入目标文件。

Special note: for the process reading from the pipe to detect EOF on that pipe, the other end has to be closed, in both processes. 特别说明:要从管道读取过程以检测该管道上的EOF,必须在两个过程中将另一端关闭。 After the fork, each process can and should close the pipe end that it doesn't intend to use. 在分叉之后,每个过程都可以并且应该关闭它不打算使用的管道末端。 The one using the write end then closes that end when it has nothing more to write to it. 然后,使用写端的那个在没有更多可写内容时将其关闭。

In other unix systems, like BSD, there's a call to connect directly two file descriptors to do what you want, but don't know if there's a system call to do that in linux. 在诸如BSD之类的其他Unix系统中,有一个调用直接连接两个文件描述符来完成您想要的操作,但不知道在Linux中是否有系统调用来做到这一点。 Anywya, this cannot be done with FILE * descriptors, as these are the instance of a buffered file used by <stdio.h> library to represent a file. 无论如何,这不能使用FILE *描述符来完成,因为这些是<stdio.h>库用于表示文件的缓冲文件实例 You can get the file descriptor (as the system knows it) of a FILE * instance by a call to the getfd(3) function call. 您可以通过调用getfd(3)函数调用来getfd(3) FILE *实例的文件描述符(系统知道)。

The semantics you are trying to get from the system are quite elaborate, as you want something to pass directly the data from one file descriptor to another, without intervention of any process (directly in the kernel), and the kernel needs for that a pool of threads to do the work of copying directly from the read calls to the write ones. 您试图从系统中获取的语义非常复杂,因为您希望某些东西直接将数据从一个文件描述符传递到另一个文件描述符,而无需任何进程的干预(直接在内核中),并且内核需要该池线程来完成直接从读取调用复制到写入调用的工作。

The old way of doing this is to create a thread that makes the work of reading from one file descriptor (not a FILE * pointer) and write to the other. 执行此操作的旧方法是创建一个线程,该线程负责从一个文件描述符(而不是FILE *指针)读取并写入另一个文件。

Another thing to comment is that the pipe(2) system call gives you two connected descriptors, that allow you to read(2) in one (the 0 index) what is write(2) n in the second (the 1 index). 要评论的另一件事是, pipe(2)系统调用为您提供了两个连接的描述符,使您可以在一个( 0索引)中read(2) ,而在第二个( 1索引)中read(2) write(2) n。 If you fork(2) a second process, and you do the pipe(2) call on both, you will have two pipes (with two descriptors each), one in each process, with no relationship between them. 如果您fork(2)第二个进程,并且对两个进程都进行了pipe(2)调用,则将有两个管道(每个都有两个描述符),每个进程中都有一个,并且它们之间没有任何关系。 You will be able only to communicate each process with itself, but not with the other (which doesn't know anything about the other process' pipe descriptors) so no communication between them will be possible. 您将只能与每个进程进行自身通信,而不能与另一个进程进行通信(该进程对另一个进程的管道描述符一无所知),因此它们之间无法进行通信。

Next is a complete example of what you try to do: 接下来是您尝试执行的操作的完整示例:

#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 */

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM