【问题标题】:hold position of FILE pointer before fseek()在 fseek() 之前保持 FILE 指针的位置
【发布时间】:2016-01-23 21:29:50
【问题描述】:

我正在尝试编写一个 C 函数,它从文件中读取第一行文本,然后使用 fseek() 和 ftell() 获取文件其余部分的大小(文件减去第一行)。

我的想法是使用第二个FILE *fp1 来获取原始FILE *fp 的位置,并将fp1 发送到带有fseek() 的文件末尾,这样我就不必移动我的原来的fp 并失去了它的位置。

这是我的代码。编译器告诉我我不能将fp1 分配给fp,因为fp1 是FILE* 而fp 是struct FILE*。

我可以通过这种方式实现我想要做的事情吗?

 FILE *fp, fp1;
 fp = fopen(filename, "r");
 if (!fp)
     return 0;

 fscanf(fp, "%1d", m); //Lines 15-18 read the first line of the file
 fscanf(fp, "%*1c");
 fscanf(fp, "%1d", n);
 fscanf(fp, "%*1c");
 fp1 = fp;         //<---------- This is my problem.
                   //how do I set fp1 to the same place in the
                   //file as fp?

 fseek(fp1, 0, SEEK_END);
 *file_size = ftell(fp1);

【问题讨论】:

  • 您可以通过将fp1 正确声明为指针来修复编译错误 - 缺少*。那是FILE *fp, *fp1;。但这不是保存文件位置的正确方法(两个指针都指向同一个打开的流,因此指向同一个文件位置)。
  • 不要贴带行号的代码,不方便剪切粘贴测试。

标签: c file-io fseek


【解决方案1】:

这只是将指针复制到文件句柄。正确的方法是在移动之前保存 ftell 结果,在移动到文件末尾后 - 再次移动。

所以:

long saved = ftell(fp);
fseek(fp, 0, SEEK_END);
*file_size = ftell(fp);
fseek(fp, saved, SEEK_SET);

【讨论】:

  • 感谢您的回复。使用 SEEK_SET 参数对 fseek() 的最后一次调用不会将 fp 重置回文件的开头吗?我尽量不这样做。
  • 没关系,我看到您已将保存为偏移量。我用了你的建议,它奏效了。非常感谢!
  • 请注意,此方法不是获取文件大小的可靠方法。它不适用于设备、管道、终端......并且不保证适用于文本文件。
【解决方案2】:

您的定义没有定义 2 个FILE * 指针:

FILE *fp, fp1;

fp 是 FILE *,但 fp1 被定义为 FILE 类型。

您不能以这种方式定义FILE 对象,它们只能从fopen() 获得。它们的状态不能通过复制FILE 对象来保存,这太复杂了,并且除了FILE 对象之外还使用其他资源,这可能是一个不完整的类型。

好消息是您可以使用ftell() 将当前偏移量保存在fp 中并寻找到最后以尝试获取文件大小,然后通过再次调用fseek() 来恢复流位置:

long saved = ftell(fp);
*file_size = -1;  // file size may be impossible to retrieve
if (fseek(fp, 0, SEEK_END) != -1) {
    *file_size = ftell(fp);
}
fseek(fp, saved, SEEK_SET);

但你应该注意,这种方法并不可靠:

  • 不保证适用于文本文件。
  • 它可能不适用于设备、管道、终端、特殊文件...

您应该尝试修改您的方法,使其不需要知道文件大小。

【讨论】:

  • 我合并了您的错误检查,谢谢。如果我使用 C++,我会寻找带有 cin.peek() 的 eof,但我对 C 的熟练程度不高。使用 fopen() 是否保持类似的 eof 标志?我想我对此的进一步问题不一定是这个问题的一部分。
  • fopen 不维护 eof 标志。在 C 中,只有通过尝试读取 FILE* 才能知道自己处于流的末尾。你可以这样写:int peekc(FILE*fp) { int c = getc(fp); if (c != EOF) ungetc(c, fp); return c; } 并使用if (peekc(fp) == EOF) 作为文件结束的测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
  • 2020-12-17
  • 1970-01-01
  • 2014-11-19
相关资源
最近更新 更多