Как вывести в файл с информацией из трубы в C? - PullRequest
1 голос
/ 18 февраля 2010

Я запутался в том, что я делаю неправильно, когда я пытаюсь вывести файл после того, как выполнил вторую программу.

Скажем, у меня есть входной файл со следующими именами:

Марти Б. Бич 7 8
Захарий б. Whitaker 12 23
Иван Санчес 02 15
Джим Toolonganame 9 03

После того, как мои программы закончатся, он преобразует имена учеников в их имена пользователей и выводит их в файл, подобный следующему:

mbb0708
zbw1223
is0215
jt0903

В настоящее время, когда моя программа стоит, она ничего не выводит в файл, и терминал, кажется, находится в бесконечном цикле, несмотря на то, что раньше я сам тестировал мою программу-конвертер и проверял, правильно ли она выводит имена в stdout.

Я не уверен, что я здесь делаю не так? Первое программирование с трубами. Я знаю, что нужно использовать команды чтения и записи для извлечения данных, но с помощью команды dup2 это необходимо только для одной команды чтения?

manager.c

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

int main(int argc, char** argv)
{
    pid_t pid;

    int nbytes;

    /*Buffer to hold data from pipe*/
    char buffer[BUFSIZ + 1];

    /*Pipe Information*/
    int commpipe[2];
    if(pipe(commpipe))
    {
        fprintf(stderr, "Pipe failed.\n");
        return EXIT_FAILURE;
    }

    if((pid = fork()) == -1)
    {
        fprintf(stderr,"Fork error. Exiting.\n"); 
        exit(1);
    }
    else if(pid == 0)
    {
        /*This is the child process. Close our copy of the write end of the file descriptor.*/
        close(commpipe[1]);
        /* Connect the read end of the pipe to standard input*/
        dup2(commpipe[0], STDIN_FILENO);
        /*Program will convert the Student's name to their respective names*/
        execl("converter","converter",NULL);
        /*Exit if failure appears*/
        exit(EXIT_FAILURE);
    }
    else
    {
        FILE *file;
        file = fopen("usernames.txt","a+"); //append a file(add text to a file or create a file it does not exist)
        /*Close or copy of the read end of the file descriptor */
        //close(commpipe[1]);

        nbytes = write(commpipe[1], buffer, BUFSIZ);

        //Read from pipe here first? 

        //Output to usernames.txt the usernames of the user from the pipe.
        fprintf(file, "%s", buffer);

        /*Wait for the child process to finish*/
        waitpid(pid, NULL, 0);
    }

    return 0;
}

Ответы [ 3 ]

1 голос
/ 18 февраля 2010

Одна проблема заключается в том, что после того, как менеджер отправил все данные в конвертер, менеджер не закрывает commpipe[1]. Из-за этого конвертер никогда не получит EOF на stdin, поэтому не выйдет.

Скорее всего, менеджер не получает данные из конвертера из-за буферизации. Некоторые реализации stdio используют буферизацию с полным буфером (в отличие от буферизации строк), когда запись не ведется на терминал. Как только вы исправите предыдущую ошибку и закроете процесс, это очистит стандартный вывод. Вы также можете рассмотреть возможность добавления fflush(stdout) после вашей линии пут.

0 голосов
/ 18 февраля 2010

Как я понимаю, ваша программа-конвертер читает строки из стандартного ввода и записывает их в стандартный вывод. Поскольку канал является однонаправленным объектом, вам потребуется ДВА из них для связи с менеджером - один для отправки данных в преобразователь и один для получения выходных данных.

Возможно, вам следует рассмотреть возможность расширения конвертера, чтобы он принимал (в качестве необязательных аргументов) имя входного и выходного файла.

0 голосов
/ 18 февраля 2010

Посмотрите на сайт OpenGroup , есть пример, похожий на ваш. Я предлагаю вам сначала получить образец, работающий с жестко заданным кодом. Как только это сработает, добавьте код для чтения и запишите результаты.

Я внес некоторые незначительные изменения, чтобы пример работал:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>

int main(int argc, char** argv){
   int fildes[2];
   const int BSIZE = 100;
   char buf[BSIZE];
   ssize_t nbytes;
   int status;


   status = pipe(fildes);
   if (status == -1 ) {
       /* an error occurred */
       printf("Error!\n");
       exit(-1);
   }

   printf("Forking!\n");
   switch (fork()) {
   case -1: /* Handle error */
       printf("Broken Handle :(\n");
       break;


   case 0:  /* Child - reads from pipe */
       printf("Child!\n");
       close(fildes[1]);                       /* Write end is unused */
       nbytes = read(fildes[0], buf, BSIZE);   /* Get data from pipe */
       /* At this point, a further read would see end of file ... */
       assert(nbytes < BSIZE);                 /* Prevent buffer overflow */
       buf[nbytes] = '\0';                     /* buf won't be NUL terminated */
       printf("Child received %s", buf);
       close(fildes[0]);                       /* Finished with pipe */
       fflush(stdout);
       exit(EXIT_SUCCESS);


   default:  /* Parent - writes to pipe */
       printf("Parent!\n");
       close(fildes[0]);                       /* Read end is unused */
       write(fildes[1], "Hello world\n", 12);  /* Write data on pipe */
       close(fildes[1]);                       /* Child will see EOF */
       /* Note that the Parent should wait for a response from the
       child here, because the child process will be terminated once
       the parent exits */
       exit(EXIT_SUCCESS);
   }

   return 0;
}
...