使用 fseek 比使用 C 中的 fread 序列有什么优势?

What is the advange of using fseek over using a sequence of fread in C?

我是C编程初学者,对如何处理文件有一些疑问。

让我们假设我们有一个存储了 N 个 int 值的二进制文件。 假设我们要读取文件中的第 i 个值。

使用 fseek 将文件指针定位到第 i 个 int 值并在 fseek 之后读取它而不是使用一系列 i fread 调用是否有真正的优势?

直觉上,我认为 fseek 更快。但是函数如何在不读取中间信息的情况下找到文件中的第i个值?

我认为这取决于实现。所以,我试图找到fseek函数的实现,但没有成功。

But how the function finds the i-th value in the file without reading the intermediary information?

没有。由您提供正确的(绝对或相对)偏移量。例如,您可以请求将文件指针前进 i*sizeof(X).

它仍然需要按照文件所在的扇区链来找到正确的扇区,但这不需要读取这些扇区。该元数据存储在文件本身之外。

Is there any real advantage of using fseek for positioning the file pointer to the i-th int value and reading it after the fseek instead of using a sequence of i fread calls?

每个级别都有潜在的好处。

通过查找,系统可能不得不从磁盘读取更少。系统以扇区的形式从磁盘读取,因此由于缓存,短寻道可能没有这个好处。但是遍历整个扇区可以减少需要从磁盘中获取的数据量。

同样,通过查找,stdio 库我必须从 OS 请求更少。 stdio 库通常读取的内容比它需要的多,因此以后对 fread 的调用不需要触及 OS 或磁盘。短查找可能不需要进行任何系统调用,但超出缓冲数据末尾的查找可能会减少从 OS.

中获取的数据总量

最后,在使用 fseek 时,无论您寻找多远,都不需要将跳过的数据从 stdio 库的缓冲区复制到用户的缓冲区。

哦,别忘了您考虑的是 i-1 读取而不是大读取。这些读取中的每一个都在库(错误检查)和调用者(错误处理)中消耗 CPU。

Is there any real advantage of using fseek for positioning the file pointer to the i-th int value and reading it after the fseek instead of using a sequence of i fread calls?

是的,如果您想从文件中读取一个值并且知道它在哪里,则没有理由读取其他任何内容。

Intuitively, I think that fseek is faster. But how the function finds the i-th value in the file without reading the intermediary information?

您的直觉是正确的,如果您读取一个值,按理说它会比读取多个值更有效。它找到值的方式很简单,一般来说文件中的每个位置对应1个字节,如果你传递一个偏移量,比如7,下一次读取将从第8个字节开始,假设你的文件有以下数据:

 -58 10 12  14 7 9
^      ^
|      |
0      offset of 7

fseek(fp, 7, SEEK_SET);

if(fscanf(fp,"%d",&num) == 1 ){  
    printf("%d", num);
}  

会输出12.

文件指针设置到第7位,则从下一个字节开始读取。就好像你有一个数组,你想访问第 7 个位置,你只需要使用 arr[7].

I think that this is implementation-dependent.

虽然有一些小细节可以定义实现,但整体行为是标准化的。

§7.21.9.2 The fseek function

Synopsis

1.

#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);

Description:

  1. The fseek function sets the file position indicator for the stream pointed to by stream. If a read or write error occurs, the error indicator for the stream is set and fseek fails.

  2. For a binary stream, the new position, measured in characters from the beginning of the file, is obtained by adding offset to the position specified by whence. The specified position is the beginning of the file if whence is SEEK_SET, the current value of the file position indicator if SEEK_CUR, or end-of-file if SEEK_END. A binary stream need not meaningfully support fseek calls with a whence value of SEEK_END.

  3. For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET.

  4. After determining the new position, a successful call to the fseek function undoes any effects of the ungetc function on the stream, clears the end-of-file indicator for the stream, and then establishes the new position. After a successful fseek call, the next operation on an update stream may be either input or output.

Returns:

  1. The fseek function returns nonzero only for a request that cannot be satisfied.