C语言中popen()函数的使用失败?

4

我可以在Linux终端中运行以下命令:

xwd -root | xwdtopnm | pnmtojpeg > screen.jpg

它会生成一个当前屏幕的截图。

我尝试使用下面的代码来实现同样的功能:

#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

在处理二进制数据时,不应使用fgetsputsfgets会在遇到换行符时停止读取。更糟糕的是,puts会输出额外的换行符,并且当其遇到\0时也会停止输出。应改用freadfwrite


抱歉,我的意思是fread和fwrite,而不是read和write。(我刚刚编辑了我的回答) - Laurence Gonsalves

2

对于遇到同样问题的人,我最终通过使用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);
}

1
只要确保不在同一文件上执行缓冲IO(fread,fscanf,fwrite,fprintf,...)和非缓冲IO(read,write,...),这就没问题了。不过我不明白为什么你不直接使用fread和fwrite。 - ephemient

2
函数和不适用于像图像文件这样的二进制数据。它们只能用于文本字符串。在C语言中,字符串以空字节('\0')结尾。由于这实际上只是一个零,因此它可能出现在二进制文件的任何位置。假设line[]填充有256个字符的数据。当您调用函数时,该函数读取数组,直到遇到空字节,然后假定已经到达字符串的末尾并停止。由于在二进制文件中空字节可能随时出现(而不仅仅在数组的末尾),因此函数可能无法打印出数据的某些部分。
如果我是您,我会研究和函数,并使用它们代替。在Linux机器上,您只需键入即可阅读两个函数的文档。

0

没有测试你的代码,我怀疑"xwd -root | xwdtopnm | pnmtojpeg"作为C-Pipe的参数是否有效。

无论如何,我不会使用C程序来解决这个问题。相反,使用一个简单的Bash脚本。


我不能使用Bash脚本,这只是一个测试。我需要一种编程方式在X11中获取屏幕截图,而这是我能想到的最好的方法,而不必浏览所有X11源代码。 - mattg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接