Как читать из трубы в файл? - PullRequest
0 голосов
/ 17 апреля 2020

Я хотел бы прочитать из канала прямо в файл с кодом ниже. base_fd - это канал.

FILE* fp = fopen("dec_data", "wb+"); 
int r_result; 
int len = msg_length-part-3;  //set to 75933
while ((r_result = read(base_fd[0], fp, len))) {
       printf("r_result: %d \n", r_result);
       len -= r_result; 
       }

Кажется, что чтение выполнено нормально, r_result показывает 65536, а затем 10397, как требуется. Однако, когда я проверяю созданный мной файл, он имеет размер 0 байт ...

1 Ответ

0 голосов
/ 18 апреля 2020

В вашем коде ошибка semanti c. Взгляните на read (2) подпись системного вызова:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

Вторым параметром функции является указатель void (void *buf), где read будет хранить count байтов, которые он читает из дескриптора fd.

Однако FILE * является абстракцией C library. В этом ответе вы можете увидеть больше этого. struct FILE в MinGW32 5.1.4 это:

typedef struct _iobuf
{
    char*   _ptr;
    int _cnt;
    char*   _base;
    int _flag;
    int _file;
    int _charbuf;
    int _bufsiz;
    char*   _tmpfname;
} FILE;

То, что будет делать чтение, аналогично тому, как мы копируем строки. Рассмотрим эту функцию:

void strcpy(char *dst, char *src)
{
    while(*src) *dst++ = *src++;
}

Эта функция копирует содержимое из src в dst, пока не найдет завершающий байт NULL. Это, очевидно, очень некорректная функция, которую нельзя использовать, но она показывает, почему ваш пример не работает.

Под капотом то, что делает read, очень похоже на эту функцию strcpy: она перезаписывает много байтов в памяти, начиная с адреса, на который указывает указатель fp. Вы фактически теряете ссылку на указатель FILE * и связанные с ним ресурсы.

Держу пари, что если вы попытаетесь набрать close(fp) после этого l oop, вы получите ошибка сегментации (это неопределенное поведение, но я все равно сделаю ставку).

Правильный способ сделать то, что вы хотите:

FILE* fp = fopen("dec_data", "wb+"); 
char *buf;
int r_result; 
int len = msg_length - part - 3;  //set to 75933

buf = malloc(len);
if(!buf) {
    perror("malloc");
    exit(EXIT_FAILURE);
}

while ((r_result = read(base_fd[0], buf, len))) {
    fprintf(fp, buf);
    len -= r_result; 
}

free(buf);
close(fp); // now it closes the file pointer
...