неудачное использование popen () в C? - PullRequest
4 голосов
/ 08 мая 2009

Я могу запустить следующую команду

xwd -root | xwdtopnm | pnmtojpeg > screen.jpg

в терминале под Linux, и он выдаст скриншот моего текущего экрана.

Я пытаюсь сделать следующее с кодом:

#include <stdio.h>
#include <stdlib.h>
int main()
{
   FILE *fpipe;
   char *command="xwd -root | xwdtopnm | pnmtojpeg";
   char line[256];

   if ( !(fpipe = (FILE*)popen(command,"r")) )
   {  // If fpipe is NULL
      perror("Problems with pipe");
      exit(1);
   }

   while ( fgets( line, sizeof line, fpipe))
   {
      //printf("%s", line);
      puts(line);
   }
   pclose(fpipe);
}

, затем я компилирую и запускаю программу ./popen > screen.jpg, но полученный файл screen.jpg не может быть изменен Как я могу сделать это, чтобы я мог правильно передать свою программу?

Ответы [ 4 ]

7 голосов
/ 08 мая 2009

Вы не должны использовать fgets и puts для работы с двоичными данными. fgets остановится, когда увидит новую строку. Хуже того, puts выведет дополнительные символы новой строки и также остановится всякий раз, когда встретится с \ 0. Вместо этого используйте fread и fwrite.

2 голосов
/ 09 мая 2009

Для тех, у кого возникла такая же проблема, я наконец-то начал работать с помощью системных вызовов Unix для чтения / записи:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

//writes to an output file test.jpg directly
int main()
{
    FILE *fpipe;
    char *command="xset b off  && xwd -root | xwdtopnm 2> /dev/null | pnmtojpeg";
    char buff[256];
    size_t result_write;
    size_t result_read;

    if ( !(fpipe = (FILE*)popen(command,"r")) )
    {  // If fpipe is NULL
        perror("Problems with pipe");
        exit(1);
    }

    int dest_fd = open("test.jpg",  O_RDWR|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR );
    int fd = fileno(fpipe);
    while((result_read = read(fd, buff, sizeof(char)*256))>0){  
        if(result_read < 0){
            perror("Problem while reading.\n");
            exit(1);
        }
        result_write = write(dest_fd, buff, sizeof(char)*256);
        if(result_write < 0){
            perror("Probelms writing to outputfile.\n");
            exit(1);
        }   
    }
    close(dest_fd);     
   pclose(fpipe);
}
2 голосов
/ 08 мая 2009

Функции fgets и puts не предназначены для использования с двоичными данными, такими как файлы изображений. Они должны использоваться только со строками текста. В C строки заканчиваются нулевым байтом ('\0'). Поскольку на самом деле это просто ноль, он может появиться в любом месте двоичного файла. Допустим, что line[] заполнено 256 символами данных. Когда вы вызываете puts, функция читает массив до тех пор, пока не встретит нулевой байт, затем предполагает, что он достиг конца строки и остановился. Поскольку в двоичном файле нулевой байт может появиться где угодно (и не только в конце массива), функция puts может легко не распечатать части ваших данных.

На вашем месте я бы исследовал функции fread и fwrite и использовал бы их вместо этого. На компьютере с Linux вы должны просто набрать man 3 fread, чтобы прочитать документацию для обеих функций.

0 голосов
/ 08 мая 2009

Без тестирования вашего кода я сомневаюсь, что «xwd -root | xwdtopnm | pnmtojpeg» работает в качестве аргумента для C - Pipe.

Я бы не стал использовать программу на Си для такой проблемы. Вместо этого используйте простой скрипт Bash.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...