C回滚来自命令输出的FILE指针

时间:2015-04-09 05:28:33

标签: c file-io io command

我有一个命令输出有问题,当我尝试使用rewind或fseek重新加注并检查输出命令做其他东西它不起作用时,这是部分代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
int  main(){
     FILE *pf;
     int nhd=1;
     size_t b_size = 80;
     char *data = malloc(b_size * sizeof(char));
     pf = popen("/sbin/mycmd -s","r");

     while(-1 != getline(&data, &b_size, pf))
          nhd++;

     fseek (pf , 0 , SEEK_SET); // rewind(pf);

     while(-1 != getline(&data, &b_size, pf))
          nhd++;
     printf("%i\n",nhd);
     pclose(pf);
     free(data);
} 

它应该输出命令行数的两倍,但是当我使用真实文件时,它会倒带或者什么都不起作用。我该怎么办?

2 个答案:

答案 0 :(得分:2)

并非所有流都是可搜索的,例如那些具有短暂内容的流,例如管道或套接字。根据{{​​1}}:

  

fseek函数仅对无法满足的请求返回非零值。

所以你真的需要检查一下它是否有效。并使用C11 7.21.9.2 The fseek function /6而不是fseek()进行检查,后者不会给出任何错误指示。

一种方法是预先读取十个字节,然后尝试回到开头。如果有效,继续进行,就像它可以寻找一样。如果没有,请痛苦地抱怨并退出。

如果

>

例如,即使数据来自管道的标准输入,也没有什么能阻止您在阅读时将其写入临时文件并在需要备份时使用该文件某点。

它可能变得复杂,因为您需要决定是从临时文件中读取还是读取管道中的新数据,但有时复杂性很难避免。

答案 1 :(得分:2)

如果您真的特意尝试将输出加倍,并且fd不是文件,请省略fseek()并关闭管道并重新打开它并再次执行读取循环。此外,nhd应该从0开始,而不是1,以获得准确的读取行数。如果您的目标更为复杂,那么您应该指明您的目标。我并不感到惊讶fseek()不会处理非文件。文档引用文件,但含糊不清地指示“流”。以及

更新:注释表明输入双通的原因是预先计数以确定要分配的数量。或者,使用链接列表使用malloc()动态分配数据,从而无需预先计算/预分配:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 256

typedef struct list {
    struct list *next;
    char *string;
} LIST;

LIST *head, *p;

int 
main(int argc, argv) 
{
    FILE *fp;
    char line[MAX_LINE];

    if ((fp = fopen(argv[1], "r")) == NULL) {
         fprintf(stderr, "Error opening %s\n", argv[1]);
         exit(-1);
    }
    while(fgets(line, sizeof(line), fp)) {
        LIST *n = malloc(sizeof(LIST));  
        n->string = strdup(line);
        n->next = NULL;
        p = (head == NULL) ? head = n : p->next = n;
    }
    fclose(fp);

    for(p = head; p; p != NULL; p->next)
        printf("%s", p->string);

    // 
    // . . . do whatever
    // 

    /*
     * Free list when unneeded
     */
    for(p = head; p != NULL; ) {
        printf("%s", p->string);
        LIST *saved = p->next
        free(p->string);
        free(p);
        p = saved;
    }
    return 0;
}