unsuccessful use of popen() in C?

2019-05-08 07:07发布

I can run the following command

xwd -root | xwdtopnm | pnmtojpeg > screen.jpg

in a terminal under linux and it will produce a screenshot of my current screen.

I try to do the following with the code:

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

then I compile and run the program ./popen > screen.jpg but the resulting file screen.jpg is unrecongizable. How can I do this so that I can pipe through my program correctly?

4条回答
Evening l夕情丶
2楼-- · 2019-05-08 07:25

The functions fgets and puts aren't intended to be used with binary data like image files. They should only be used with strings of text. In C, strings end with a null byte ('\0'). Since that's really just a zero, it might appear anywhere in a binary file. Let's say that line[] is filled with 256 characters of data. When you call puts, the function reads the array until it encounters a null byte then assumes it has reached the end of the string and stops. Since in a binary file a null byte might appear anywhere (and not just at the end of the array), the puts function could easily fail to print out sections of your data.

If I were you, I'd research the fread and fwrite functions and use them instead. On a Linux machine, you should just be able to type man 3 fread to read documentation for both functions.

查看更多
放荡不羁爱自由
3楼-- · 2019-05-08 07:27

Without testing your code I hav doubts that "xwd -root | xwdtopnm | pnmtojpeg" works as an argument for a C - Pipe.

I wouldn't use a C program anyway for such a problem. Use a simple Bash script instead.

查看更多
Deceive 欺骗
4楼-- · 2019-05-08 07:36

You shouldn't use fgets and puts for dealing with binary data. fgets will stop whenever it sees a newline. Worse, puts will output extra newlines and it will also stop whenever it runs into a \0. Use fread and fwrite instead.

查看更多
Fickle 薄情
5楼-- · 2019-05-08 07:43

For those having this same problem, I ended up finally getting it working by using the Unix read/write system calls:

#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);
}
查看更多
登录 后发表回答