【问题标题】:unsuccessful use of popen() in C?在 C 中使用 popen() 失败?
【发布时间】:2009-05-08 10:35:37
【问题描述】:

我可以运行以下命令

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 &gt; screen.jpg,但生成的文件 screen.jpg 无法识别。我怎样才能做到这一点,以便我可以正确地通过我的程序?

【问题讨论】:

    标签: c screenshot popen piping x11


    【解决方案1】:

    您不应该使用fgetsputs 来处理二进制数据。 fgets 将在看到换行符时停止。更糟糕的是,puts 将输出额外的换行符,并且它也会在遇到 \0 时停止。请改用freadfwrite

    【讨论】:

    • 对不起,我的意思是 fread 和 fwrite,而不是 read 和 write。 (刚刚编辑了我的答案)
    【解决方案2】:

    函数fgetsputs 不适用于图像文件等二进制数据。它们只能与文本字符串一起使用。在 C 中,字符串以空字节 ('\0') 结尾。由于这实际上只是一个零,它可能出现在二进制文件的任何位置。假设line[] 填充了 256 个字符的数据。当您调用puts 时,该函数会读取数组,直到遇到空字节,然后假定它已到达字符串的末尾并停止。由于在二进制文件中,空字节可能出现在任何地方(而不仅仅是在数组的末尾),puts 函数很容易无法打印出您的数据部分。

    如果我是你,我会研究 freadfwrite 函数并改用它们。在 Linux 机器上,您应该只需键入 man 3 fread 即可阅读这两个函数的文档。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 只要确保不对同一个文件执行缓冲 IO (fread, fscanf, fwrite, fprintf, ...) 和非缓冲 IO (read, write, ...),这应该没事。不过,不明白你为什么不只使用 fread 和 fwrite。
      【解决方案4】:

      在没有测试您的代码的情况下,我怀疑“xwd -root | xwdtopnm | pnmtojpeg”是否可以作为 C 管道的参数。

      无论如何我都不会使用 C 程序来解决这样的问题。请改用简单的 Bash 脚本。

      【讨论】:

      • 我不能使用 Bash 脚本,这只是一个测试。我需要某种编程方式在 X11 中截取屏幕截图,这是我能想到的最好的方法,而无需查看所有 X11 源代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-12
      • 1970-01-01
      相关资源
      最近更新 更多