C 语言 fseek() vs rewind()

2025年3月17日 | 阅读13分钟

在本文中,我们将讨论 C 语言中 fseek()rewind() 函数的区别。但在讨论区别之前,我们必须了解 C 语言中的 fseek()rewind() 函数。

fseek()

C 编程语言中的 fseek() 函数用于将文件位置指示器重新定位到文件内预先确定的位置,通常称为 文件指针。您可以使用它来更改下一个 写操作在文件中的发生位置。此函数是 C 标准库 的一部分,通常与文件流(FILE 指针)结合使用以执行文件操作。

C 标准库中的 fseek() 函数的功能在不同系统或实现之间可能存在很大差异。但是,该函数的目标和行为总体上符合 C 标准。

fseek() 函数将指定文件流的文件位置指示器调整到指定位置。每个文件流都有一个称为 文件位置指示器 的概念,它指定了下一个读写操作在文件中的发生位置。

语法

fseek() 的语法如下

参数

Stream: 指向 FILE 对象 的引用,表示所需 文件流

Offset: 它表示文件指针必须移动的字节数。根据移动方向,它可以是 正值负值

Origin: 从该点开始应用偏移量。它可以是以下三个值之一

SEEK_SET (0): 偏移量从 文件开头 计算。

SEEK_CUR (1): 偏移量是相对于文件指针的 当前位置

SEEK_END (2): 它是相对于 文件末尾 的。

返回值

如果操作成功,则返回 0。如果发生错误,则返回非零值。

fseek() 方法 返回一个 整数结果,以指示操作是成功还是失败。如果操作成功,则返回 0;否则,返回非零值。如果发生问题,您可以使用 errno 变量perror() 函数 了解有关具体错误的更多信息。

需要注意的是,只有在二进制文件上,fseek() 的行为才符合预期。由于不同操作系统在行尾协议上的差异,在文本文件上使用 fseek() 函数 可能会产生意外结果。通常建议使用 fgetc()fgets() 等方法从文本文件的特定行读取。

程序

这是一个使用 C 语言 fseek() 函数的示例程序。在此程序中,将创建一个简单的 文本文件,向其中写入一些数据,然后使用 fseek() 从文件的给定位置读取并输出数据。

输出

This is line 3.

说明

在此示例中,包含所需的头文件 stdio.h,用于进行常规 输入/输出操作。我们指定 main() 函数,这是我们程序开始的地方。

声明了三个变量

FILE *file: 指向文件流的指针,将用于与文件交互,存储在 FILE*file 变量中。

const char *filename: 我们希望创建和操作的文件名,存储在 char *filename 变量中的常量字符串 "example.txt" 中。

char buffer[100]: 100 个字符的字符数组(缓冲区),将用于存储从文件中检索到的信息。

  • 文件以 写模式 ("w") 打开。如果文件不存在,则会被创建。如果文件打开失败,我们将使用 perror() 函数 输出 错误消息 并返回 错误代码
  • 使用 fputs() 函数,将三行数据写入文件。每次调用 fputs() 时,一行文本会被写入文件,并用 换行符 (n) 分隔。
  • 在将数据写入文件后,我们使用 fclose() 函数关闭文件。
  • 之后,文件以 读模式 ("r") 重新打开,以便我们可以从中读取数据。如果文件打开失败,我们将使用 perror() 函数打印 错误消息 并返回 (1)错误代码
  • 通过使用 fseek() 函数文件指针 移到文件开头,然后两次调用 fgets() 来读取文件的前两行。但是,由于我们没有将它们存储在任何变量中,因此有效地绕过了这两行。
  • 文件指针 目前位于 第三行 的开头。使用 fgets() 从文件中读取每一行,并将其存储在缓冲区数组中,这在一个 while 循环 中完成。当文件中没有更多要读取的行时,fgets() 函数 返回 NULL,循环一直持续到那时。
  • 之后,我们使用循环中的 printf() 函数打印缓冲区数组中的每一行。
  • 读取打印 了每一行之后,我们使用 fclose() 关闭文件。
  • main 函数返回 0,表示程序已成功运行。
  • 此程序首先创建一个名为 "example.txt" 的文本文件,并向其中插入三行数据。之后,它将 读取打印 从第三行开始的文件内容。通过使用 fseek() 函数,程序有效地跳过了前两行,然后在循环中使用 fgets() 读取并打印后续行。最后,它终止文件并优雅地结束。

复杂度分析

时间复杂度

使用 fputs() 函数向文件写入数据,每次调用需要 O(1) 的时间复杂度。

由于 fgets() 读取字符直到遇到 换行符 或达到设定的缓冲区大小,因此在循环内从文件中读取数据需要 O(n) 的时间复杂度,其中 n 是文件中的字符数。

程序的总 时间复杂度 可估计为 O(n),其中 n 是输入文件的总字符数。

空间复杂度

程序 空间复杂度 的主要决定因素是用于保存从文件中读取的每一行的 缓冲区大小。在此实例中,缓冲区大小设置为 100 个字符 (char buffer[100])

其他程序 变量 的内存需求,例如文件指针 FILE *file 和常量字符串 const char *filename,是恒定的,与输入大小无关。

由于程序使用了固定大小的缓冲区来保存从文件中读取的行,因此其空间复杂度为 O(1)。随着输入大小的增加,空间复杂度保持不变。

rewind()

C 编程中的 rewind() 标准库函数用于将文件位置指示器 重置 到文件的开头。它是 C 标准库 (stdio. h) 的一部分,最常见的用法是在 写数据 之后重置文件指针,以便您可以再次从文件开头读取。

C 编程中的标准库方法 rewind() 用于将文件位置指示器重置到文件的开头。它旨在处理文件流 (FILE 指针),并在头文件 stdio.h 中指定。rewind() 函数使您能够在执行了 prior 文件操作后将文件指针移回到文件开头,从而允许您再次从文件开头读写数据。

C 语言中的 rewind() 函数对文件流(由 FILE 引用表示)进行操作,不接受任何 输入参数。它通过重置指定文件流的文件位置指示器来开始下一个 写操作,从头开始。

语法

参数

Stream: 指向 FILE 对象的指针,表示需要重置文件位置指示器的 文件流

返回值

由于 rewind() 函数是 void 函数,所以它没有返回值。

用途

rewind() 的主要功能使您能够在到达文件末尾或完成 prior 文件操作后,再次从文件开头 读取数据。如果您需要多次处理文件或想在不重新访问文件的情况下从头开始读取内容,它会特别有用。

请记住,rewind() 函数通常与二进制文件或具有固定长度记录结构的文件一起使用。如果您处理具有可变长度行尾的文本文件(例如 Unix-like 平台或 Windows 上的 n),rewind() 函数 可能会提供意外的结果。在处理文本文件时,您可以使用其他技术或谨慎使用 fseek()

程序

输出

Read: Hello, this is a sample file.
Read again: Hello, this is a sample file.

说明

  • 在此示例中,我们包含了进行常规 输入/输出 所需的 头文件
  • 定义 main() 函数,这是我们程序开始的地方。
  • 之后,创建一个 文件指针变量 来处理文件。使用 fopen() 函数以 读模式 ("r") 打开文件。
  • 在此步骤中,我们使用 fopen() 函数尝试以只读模式打开文件 "example.txt"。如果尝试打开文件失败(返回 NULL),则表示文件不存在或无法打开。在这种情况下,我们使用 perror() 函数打印 错误消息 并返回错误代码 (1)。
  • 使用 fgets() 函数从文件读取一些数据。
  • 使用 fgets() 函数从文件读取一行文本并将其存储在缓冲区数组中。fgets() 函数从文件读取字符,直到达到缓冲区容量 (sizeof(buffer)) 或遇到新行。之后,在读取的字符串末尾添加一个空终止符 ('0'),将其转换为可用的 C 字符串。使用 printf() 函数,我们输出缓冲区的内容。
  • 使用 rewind() 函数将文件位置指示器重置到文件开头。
  • 在此阶段,将文件指针 file 作为参数传递给 rewind() 函数。当 rewind() 函数重置文件位置指示器时,与之关联的文件流将被移动到文件开头。这使我们能够从开头再次访问文件中的 prior 内容。
  • 使用 fgets() 函数,再次从文件开头读取文件。
  • rewind() 重置文件位置指示器后,我们现在可以再次调用 fgets() 函数从文件开头读取一行。换行符会被存储在缓冲区数组中,然后使用 printf() 函数打印出来。
  • 使用 fclose() 函数关闭文件。
  • 我们使用 fclose() 函数关闭文件,以释放与文件流相关的系统资源。
  • 如果程序成功,main 函数返回 0。
  • 如果程序打开一个文件,读取一行文本,使用 rewind() 函数将文件位置指示器移回开头,然后再次从文件开头读取一行。之后,它通过关闭文件礼貌地结束。借助 rewind() 函数,我们无需重新打开文件即可反复从文件开头读取数据。

复杂度分析

时间复杂度

使用 fopen() 打开文件: 打开文件通常被认为具有 O(1) 的时间复杂度。它取决于操作系统和底层文件系统管理文件操作的效率,而不是直接取决于文件的大小。

使用 fgets() 从文件读取一行文本: Fgets() 具有 O(n) 的时间复杂度,其中 n 是从文件中读取的字符数。在此实例中,它读取到 sizeof(buffer),在提供的代码 (100) 中是一个固定值,并从文件中读取字符。

使用 rewind() 清除文件位置指示器: rewind() 函数以恒定时间或 O(1) 的时间将文件位置指示器移动到文件开头。

使用 fgets() 从文件读取更多内容: 如前所述,fgets() 所需的 时间O(n),其中 n 是从文件中读取的总字符数。在此实例中,它再次从文件中读取到 sizeof(buffer),这是一个 固定值 (100)

提供的代码的总 时间复杂度 可以粗略计算为 O(n),其中 n 是第一次和第二次 fgets() 调用中读取的字符总数,或从文件中读取的总字符数。

空间复杂度

文件变量: 无论 文件大小 或读取的字符数如何,文件指针 FILE *file 使用恒定空间,即 O(1)

缓冲区数组: 缓冲区数组中的字符数组 char buffer[100] 的大小固定为 100 个字符。由于缓冲区大小是恒定的,因此它具有 O(100)O(1) 的空间复杂度。

由于提供的代码使用了固定大小的缓冲区,并且其内存使用量与 输入文件输入数据 的大小无关,因此其总体 空间复杂度O(1)

fseek() 和 rewind() 的比较

fseek() vs rewind() in C

C 语言中的 fseek()rewind() 函数都用于定位文件,但服务于不同的目的。Rewind() 更简单,因为它始终将文件指针重置到开头。但是,fseek() 提供了对文件指针位置更精确的控制,包括偏移量和起始点参数。您应该使用哪种例程将取决于您特定的文件处理需求以及您对文件指针位置所需的控制程度。fseek() 函数rewind() 函数在多个方面存在差异。

功能

fseek()

  • fseek() 函数可用于将 文件位置指示器 设置到文件内的特定位置。它允许使用偏移量和起始点选项(SEEK_SET、SEEK_CURSEEK_END)将文件指针移动到任何位置。

rewind()

  • rewind() 函数不带任何其他选项,直接将文件位置指示器重置到文件开头。文件指针始终移动到文件开头。

函数签名

fseek()

  • int fseek(FILE *stream, long offset, int origin);

rewind()

  • void rewind(FILE *stream);

参数

fseek()

  • stream: 指向 FILE 对象的引用,表示所需的 文件流
  • Offset: 文件指针 必须移动的字节数。根据移动方向,它可以是 正值负值
  • Origin: 从该点开始应用偏移量。它可以是以下三个值之一
  • SEEK_SET (0): 偏移量从 文件开头 计算。
  • SEEK_CUR (1): 偏移量是关于文件指针的当前位置。
  • SEEK_END (2): 相对于文件末尾的偏移量。

rewind()

  • stream: 指向 FILE 对象的指针,表示需要重置文件位置指示器的文件流。

文件指针移动

fseek()

  • 它控制 文件指针 的放置位置,并允许在文件内更精确地移动文件指针。

rewind()

  • 无论当前位置如何,此函数始终将文件指针移动到文件开头。

用例

fseek()

  • 它有助于将文件指针移动到文件内的指定位置,例如 绕过标题 或在二进制文件中查找特定记录。
  • 它适用于您需要读写特定文件位置的情况。

rewind()

  • 当您希望 从头开始读取或写入 并将文件指针重置到文件开头时,它非常理想。
  • 它常用于您希望再次从头开始 读取数据 或需要重新处理整个文件的情况。

灵活性

fseek()

  • fseek() 中的 offsetorigin 变量 提供了更大的灵活性,使其适用于不同的文件定位需求。

rewind()

  • rewind() 函数 提供了一种简单的方法,无需任何其他选项即可将文件引用重置到文件开头。

错误处理

fseek()

  • fseek() 函数返回一个整数值。如果成功,函数返回 0。如果发生错误,则返回非零数字,通常表示文件或其位置存在问题。
  • 调用 fseek() 函数后,您可以使用 perror() 函数查找故障。

rewind()

  • Rewind() 函数返回一个无值的对象 (void)。它会自动将文件位置指示器重置到文件开头,而不会提供任何错误反馈。
  • 您必须单独处理文件打开或其他文件操作期间可能发生的潜在错误(如果有),因为 rewind() 不返回任何错误代码。

二进制文件用法

fseek()

  1. 处理二进制文件时,fseek() 尤其有用。
  2. 您可以导航到二进制文件中的特定位置,从而可以直接访问记录或数据结构。

rewind()

  1. 使用 rewind() 函数也可以处理二进制文件。
  2. 在从头开始处理二进制数据时,将文件引用重置到二进制文件开头至关重要。