3151 字
16 分钟
标准IO(三)文件操作

标准输入、标准输出和标准错误#

这3个标准I/O流通过预定义文件指针stdin、stdout和stderr引用。和文 件 描 述 符 STDIN_FILENO 、 STDOUT_FILENO 和STDERR_FILENO作用的相同。 但应区分文件流文件描述符前者用于标准IO,后者用于Unix系统IO(无缓冲IO)。


打开流函数#

fopen, fdopen, freopen#

FILE *fopen(const char *restrict pathname, const char *restrict mode);
FILE *fdopen(int fd, const char *mode);
FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream);

参数

  • const char *restrict pathname:指向要打开文件的路径名字符串(仅对 fopen()freopen() 有效)。
  • const char *mode:指定打开模式的字符串,可以是以下几种之一:
    • "r":只读方式打开文本文件。
    • "r+":读写方式打开文件。
    • "w":只写方式打开文件,若文件存在则截断为零长度;否则创建新文件。
    • "w+":读写方式打开文件,若文件存在则截断;否则创建新文件。
    • "a":追加模式,写入数据总是在文件末尾进行。
    • "a+":可读可追加模式,输出始终在文件末尾进行。
    • 可在上述模式后加上 'b' 表示二进制模式(在 POSIX 系统中无实际影响),或使用其他 glibc 扩展标志如 ex 等。
  • int fd:已打开的文件描述符(仅对 fdopen() 有效)。
  • FILE *restrict stream:指向要被重新打开的流(仅对 freopen() 有效)。

返回值

成功时返回指向 FILE 结构的指针;失败时返回 NULL 并设置 errno 来指示错误类型。

详细说明

  • 对于 fopen(),创建的新文件权限默认为 0666,受进程的 umask 影响。
  • 在读写混合操作时,应使用 fseek()fsetpos() 进行定位以符合 ANSI C 规范。
  • aa+ 模式下所有写操作都会自动定位到文件末尾。
  • 不同模式对应不同的底层 open(2) 标志,如下表所示:
fopen() modeopen() flags
rO_RDONLY
wO_WRONLY O_CREAT O_TRUNC
aO_WRONLY O_CREAT O_APPEND
r+O_RDWR
w+O_RDWR O_CREAT O_TRUNC
a+O_RDWR O_CREAT O_APPEND

读取函数#

fgetc#

int fgetc(FILE *stream);

作用
fgetc 用于从指定的文件流中读取下一个字符,并将其作为 unsigned char 转换为 int 返回。如果遇到文件结束或发生错误,则返回 EOF

参数

  • FILE *stream:指向要读取的文件流的指针。

返回值

  • 成功时返回读取到的字符(转换为 int)。
  • 如果到达文件末尾或发生错误,则返回 EOF

getc#

int getc(FILE *stream);

作用
getcfgetc 功能相同,但可能被实现为宏,并且可能会多次计算 stream 参数。

参数

  • FILE *stream:指向要读取的文件流的指针。

返回值

  • 成功时返回读取到的字符(转换为 int)。
  • 如果到达文件末尾或发生错误,则返回 EOF

getchar#

int getchar(void);

作用
getchar 等价于 getc(stdin),即从标准输入流中读取一个字符。

返回值

  • 成功时返回读取到的字符(转换为 int)。
  • 如果到达文件末尾或发生错误,则返回 EOF

fgets#

char *fgets(char s[restrict .size], int size, FILE *restrict stream);

作用
fgets 最多从指定流中读取 size - 1 个字符,并将其存储到缓冲区 s 中。读取会在遇到换行符 \n 或文件结束符时停止。如果读到了换行符,它也会被存储到缓冲区中。在字符串末尾会自动添加空字符 \0

参数

  • char *s:用于存储读取数据的缓冲区。
  • int size:缓冲区大小,最多读取 size - 1 个字符。
  • FILE *stream:指向要读取的文件流的指针。

返回值

  • 成功时返回指向 s 的指针。
  • 如果读取过程中出现错误或未读取任何字符就遇到文件结束,则返回 NULL

ungetc#

int ungetc(int c, FILE *stream);

作用
ungetc 将字符 c(转换为 unsigned char)压回到指定的文件流中,以便后续读取操作可以重新获取该字符。压回的字符将以相反顺序返回;只能保证一次压回有效。

参数

  • int c:要压回的字符。
  • FILE *stream:目标文件流。

返回值

  • 成功时返回压回的字符 c
  • 失败时返回 EOF

fputc#

int fputc(int c, FILE *stream);

作用 fputc() 将字符 c(被转换为 unsigned char)写入到指定的流 stream 中。

参数

  • int c:要写入的字符。
  • FILE *stream:指向目标文件流的指针。

返回值

  • 成功时返回写入的字符(作为 unsigned char 转换为 int)。
  • 失败时返回 EOF,并设置 errno 指示错误类型。

gets#

[[deprecated]] char *gets(char *s);

作用
gets() 用于从标准输入 (stdin) 读取一行字符串,直到遇到换行符或文件结束符 (EOF)。它会将读取的内容存储到由参数 s 指向的缓冲区中,并在末尾添加空字符 ('\0') 来终止字符串。注意:此函数极其不安全,已被弃用,永远不应使用。

参数

  • char *s:指向用于存放读取字符串的缓冲区指针。

返回值

  • 成功时返回指向缓冲区 s 的指针。
  • 如果发生错误或者在未读取任何字符时遇到文件结束,则返回 NULL
  • 由于没有进行缓冲区溢出检查,程序可能因缓冲区溢出而崩溃或被恶意利用,因此即使“成功”也可能无法保证函数正常返回。

写入函数#

putc#

int putc(int c, FILE *stream);

作用 putc() 与 fputc() 功能相同,但可能被实现为宏,并且可能会多次求值 stream 参数。

参数

  • int c:要写入的字符。
  • FILE *stream:指向目标文件流的指针。

返回值

  • 成功时返回写入的字符(作为 unsigned char 转换为 int)。
  • 失败时返回 EOF,并设置 errno 指示错误类型。

putchar#

int putchar(int c);

作用 putchar(c) 等价于 putc(c, stdout),即将字符 c 输出到标准输出流 stdout。

参数

  • int c:要输出的字符。

返回值

  • 成功时返回写入的字符(作为 unsigned char 转换为 int)。
  • 失败时返回 EOF,并设置 errno 指示错误类型。

fputs#

int fputs(const char *restrict s, FILE *restrict stream);

作用 fputs() 将字符串 s 写入到指定的流 stream 中,不包括其终止空字符 ‘\0’。

参数

  • const char *s:要写入的字符串。
  • FILE *stream:指向目标文件流的指针。

返回值

  • 成功时返回一个非负数。
  • 失败时返回 EOF,并设置 errno 指示错误类型。

puts#

int puts(const char *s);

作用 puts() 将字符串 s 输出到标准输出流 stdout,并在末尾添加一个换行符。

参数

  • const char *s:要输出的字符串。

返回值

  • 成功时返回一个非负数。
  • 失败时返回 EOF,并设置 errno 指示错误类型。

二进制IO#

fread#

size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);

作用
fread() 用于从指定的文件流中读取数据。它会读取 nmemb 个数据项,每个数据项的大小为 size 字节,并将这些数据存储到 ptr 指向的内存位置。

与之相对应的是 fwrite(),用于将数据写入文件流。

这两个函数适用于二进制数据的读写操作。

参数

  • void *restrict ptr:指向用于存放读取数据的缓冲区指针。
  • size_t size:每个数据项的大小(以字节为单位)。
  • size_t nmemb:要读取的数据项数量。
  • FILE *restrict stream:指向已打开的文件流结构体指针。

返回值

  • 成功时返回实际读取或写入的数据项个数(即:传输的字节数等于 size * 返回值)。
  • 如果在读取过程中遇到文件结束或者发生错误,则返回值会小于请求的项数(或为0)。
  • 文件位置指示器会随着成功读写的字节数向前推进。
  • fread() 不区分“文件结束”和“出错”,调用者必须使用 feof(3)ferror(3) 来判断具体原因。

fwrite#

size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);

作用

fwrite() 用于将二进制数据写入指定的文件流。它会从 ptr 指向的内存区域中取出 nmemb 个数据项,每个数据项的大小为 size 字节,并写入到 stream 流中。该函数常用于写入结构体或原始字节数据,是标准 I/O 库中进行二进制输出的重要函数。

参数

  • const void *restrict ptr:指向要写入的数据所在的缓冲区。
  • size_t size:每个数据项的大小(以字节为单位)。
  • size_t nmemb:要写入的数据项数量。
  • FILE *restrict stream:指向已打开的文件流,必须是以可写模式打开。

返回值

  • 成功时返回实际成功写入的数据项个数(即:写入的字节数 / size)。只有当 size 为 1 时,返回值才等于实际写入的字节数。
  • 如果在写入过程中出现错误,则返回值可能小于 nmemb,甚至为 0。
  • 文件的位置指示器会根据实际写入的字节数向前推进。

流的定位#

ftell#

这个函数常与 fseekrewind 一起使用,用于在文件流中定位或者记录当前读写位置。例如,在读取或写入前记录当前位置,处理完后再恢复位置。

long ftell(FILE *stream);

作用
ftell 函数用于获取指定文件流(stream)的当前文件位置指示器的值。这个值表示当前文件指针距离文件起始位置的字节数。

参数

  • FILE *stream:指向一个已经打开的文件流。

返回值

  • 成功时,返回当前文件位置指示器的值(以字节为单位)。
  • 失败时,返回 -1,并设置 errno 指示具体的错误原因。

ftello#

off_t ftello(FILE *stream);

作用
ftello 函数用于获取指定文件流的当前文件位置指示器的值。它是 ftell(3) 函数的扩展版本,返回值类型为 off_t 而非 long,以便在支持大文件的系统上处理大于 32 位的文件偏移量。

参数

  • FILE *stream:指向已打开文件流的指针。

返回值

  • 成功时,返回当前文件位置指示器的值(类型为 off_t)。
  • 失败时,返回 -1,并设置 errno 表示错误类型。

fseek#

int fseek(FILE *stream, long offset, int whence);

作用
fseek 用于设置流(stream)的文件位置指示器。新的位置以字节为单位,通过将 offset 字节加到 whence 指定的位置上来确定。如果 whence 设置为 SEEK_SET、SEEK_CUR 或 SEEK_END,则 offset 分别相对于文件开头、当前位置指示器或文件末尾。 成功调用 fseek 会清除流的文件结束指示器 撤销同一流上 ungetc 函数的任何影响。ungetc实际上只是修改了缓冲区或者内部状态,让下一个读取能重新获得那个字符。如果这时候你调用了 fseek 并且成功移动了文件位置,那么 之前“退回去”的那个字符将不再被读取。

参数

  • FILE *stream:指向要重新定位的流。
  • long offset:相对于 whence 的偏移量(单位为字节)。
  • int whence:定位的基准位置,可取以下值:
    • SEEK_SET:从文件开头开始计算偏移。
    • SEEK_CUR:从当前文件位置开始计算偏移。
    • SEEK_END:从文件末尾开始计算偏移。

返回值

  • 成功时返回 0。
  • 失败时返回 -1,并设置 errno 指示错误类型。

rewind#

void rewind(FILE *stream);

作用
rewind 函数用于将指定文件流的位置指示器重新定位到文件的开头。它等价于调用:

(void) fseek(stream, 0L, SEEK_SET)

但还有一个重要的区别:rewind 函数还会清除文件流的错误指示器(error indicator),而fseek 不会。

参数

  • FILE *stream:指向要重定位的文件流的指针。

返回值

  • rewind 函数没有返回值。

fgetpos#

int fgetpos(FILE *restrict stream, fpos_t *restrict pos);

作用
fgetpos() 函数用于获取指定文件流的当前文件位置指示器的值,并将其保存到 pos 指向的对象中。该函数提供了一种可移植的方式记录文件中的当前位置,尤其在一些非 UNIX 系统上,对于文本流的定位操作可能是唯一的方法。

参数

  • FILE *restrict stream:指向要操作的文件流。
  • fpos_t *restrict pos:指向用于保存当前位置的 fpos_t 类型对象的指针。

返回值

  • 成功时返回 0
  • 失败时返回非零值,并设置 errno 以指示错误类型。

fsetpos#

int fsetpos(FILE *stream, const fpos_t *pos);

作用
stream 指向的文件流的位置指示器设置为 pos 所指向的位置(该位置通常由 fgetpos() 获得)。

参数

  • FILE *stream:指向文件流。
  • const fpos_t *pos:指向之前由 fgetpos() 保存的位置。

返回值

  • 成功时返回 0
  • 失败时返回非零值,并设置 errno
标准IO(三)文件操作
https://milkfunc.top/posts/标准io三文件操作/
作者
CapCake
发布于
2025-07-12
许可协议
CC BY-NC-SA 4.0