【问题标题】:C Rewind FILE pointer coming from a command outputC 倒回来自命令输出的文件指针
【发布时间】:2015-04-09 05:28:33
【问题描述】:

我的命令输出有问题,当我尝试使用 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);
} 

它应该输出命令行数的两倍,但倒带或当我使用真实文件时,它无法正常工作。我该怎么办?

【问题讨论】:

  • 只能在普通文件中查找,不能在管道中查找。
  • 如果需要多次遍历输入,则必须将其保存在内存中。
  • 你需要添加错误检查,fseek应该已经返回了错误代码。

标签: c file-io io command


【解决方案1】:

如果您真的特别想将输出加倍,并且 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;
}

【讨论】:

  • 其实第一个时间是计算行数,然后我想将每一行分配给一个字符串,但是因为无法倒带而卡住了。
  • 您是否会考虑一种不同的设计模式,例如,只需通读一次,使用linked list,使用 malloc() 分配每个行条目?这样你就不需要两次读取数据。这样您就可以只分配所需的内存,而无需预先计算条目。
  • 谢谢,我试试看。
【解决方案2】:

并非所有流都是可搜索的,例如那些具有临时内容(如管道或套接字)的流。根据C11 7.21.9.2 The fseek function /6

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

所以你真的需要检查它是否有效。并用fseek()而不是rewind()检查它,后者不会给你任何错误提示。

一种方法是预先读取十个字节,然后尝试回到开头。如果这行得通,继续进行,就好像它是可搜索的一样。如果没有,请痛痛快快地退出。

如果流不可可搜索,但您需要能够备份,则需要自己存储。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    相关资源
    最近更新 更多