☰
八种顺序读写函数
2026/10/15 5:34:15 网站建设 项目流程

目录

摘要:

一:文件操作的流程

1:fopen

2:fclose

3:文件的路径

4:顺序和随机的区别

5:默认流

二:顺序读写函数

1:fputc

2:fgetc

3:fputs

4:fgets

5:fprintf

6:fscanf

7:fwite

8:fread


摘要:

本博客介绍并使用8种顺序读写函数~


一:文件操作的流程

读写的含义:

读(读出):即从文件里面读出数据----------->和scanf从键盘里面读出数据类似

写(写入):即把数据写入文件里面----------->和printf把数据写入到屏幕上类似

想对文件进行读写操作,则流程一定为:打开文件--->读/写文件--->关闭文件,而我们对文件可能是只读,可能是只写,可能是追加,可能是既读又写,所以在使用fopen打开文件的时候,函数规定需要在fopen的对应参数选择对应的打开模式~

1:fopen

FILE * fopen ( const char * filename, const char * mode )

参数解释:

参数类型说明
filenameconst char *要打开的文件名(可包含路径)
modeconst char *打开模式

函数作用:

  • 建立调用fopen的程序与filename文件之间的连接

  • 返回一个FILE *类型的指针,供后续读写操作使用

返回值:

  • 成功:返回FILE *

  • 失败:返回NULL

注意事项:

  • 返回值为FILE*,是结构体FILE的指针,通过该指针可以进行文件的相关操作

  • 必须检查返回值!后序读写前,务必先判断fopen的返回值是否为NULL

常用的打开模式如下:

文件使用方式含义如果指定文件不存在
“r” (只读)为了输入数据,打开一个已经存在的文本文件出错
“w” (只写)为了输出数据,打开一个文本文件建立一个新的文件
“a” (追加)向文本文件尾添加数据建立一个新的文件
“rb” (只读)为了输入数据,打开一个二进制文件出错
“wb” (只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab” (追加)向一个二进制文件尾添加数据建立一个新的文件
“r+” (读写)为了读和写,打开一个文本文件出错
“w+” (读写)为了读和写,建议一个新的文件建立一个新的文件
“a+” (读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+” (读写)为了读和写打开一个二进制文件出错
“wb+” (读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+” (读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

2:fclose

int fclose ( FILE * stream );

参数解释:

参数类型说明
streamFILE *参数就是fopen的返回值

函数作用:

关闭文件,并且断开程序与文件之间的连接(顺便会刷新缓冲区)

返回值:

返回值含义
0关闭成功
EOF(通常是 -1)关闭失败(如缓冲区刷新失败、无效流指针等)

注意事项:

fclose关闭文件后,安全起见,必须将 FILE * 类型的fp设为 NULL,但由于fclose一般都是代码的末尾执行,后面也不会在使用fp,所以往往会省去这一步,但加上才是更优秀的做法!

所以文件操作的整体框架就为:

#include <stdio.h> int main() { //打开⽂件 FILE* pFile = fopen("myfile.txt", "w"); //根据需求 进行⽂件读/写操作 //关闭文件 fclose(pFile); return 0; }

3:文件的路径

在调用fopen时,可以直接在第一个参数中传入文件名(如"data.txt"),此时系统会自动在当前工作目录下查找或创建该文件。当然,也可以传入完整的绝对路径"C:\\project\\data.txt"来指定任意目录位置下的文件。

某些打开模式,是要求在指定路径下必须存在目标文件的,所以当使用这些打开模式之前,需要事先手动新建目标文件,或者使用能够自动新建的写函数去创建文件;而有些打开模式发现目录不存在会自动创建文件~

4:顺序和随机的区别

顺序读写函数和随机读写函数,都是因为存在文件位置指示器这个东西,每次打开一个文件,其对应的FILE结构体中就会维护着一个文件位置指示器(也叫文件指针、文件偏移量),它记录着下一次读写操作将从文件的哪个字节位置开始!

每次使用顺序读写函数后,文件位置指示器会自动向后移动相应字节数,因此读写操作会自然地形成顺序去进行读写!

而随机读写函数,其可以修改文件位置指示器的值,可以跳跃到文件的任意位置进行读写,而不必按照顺序一个个处理,所以叫做随机读写函数!

5:默认流

❓️:那为什么scanf,printf的时候,直接使用就行了,不需要打开什么??

💡:因为c语言程序,只要运行起来,就会默认打开3个流

①:标准输入流 stdin

②:标准输出流 stdout

③:标准错误流 stderr

三个流的类型依然是 FILE*,和读写函数的参数一致,也可以理解为这一步电脑帮你省略了。

都是与FILE * stream(流)有关,流是什么?流可以是文件,从流里面读出数据,写入数据到流里面,只是不同的读写函数去读写的数据不一样,一些是把单个字符写入到流,或从流里读出单个字符,一些是字符串的读写,一些是二进制的读写


二:顺序读写函数

顺序读写函数有8种,如下:

函数名功能适用于
fgetc字符输入函数所有输入流
fputc字符输出函数所有输出流
fgets文本行输入函数所有输入流
fputs文本行输出函数所有输出流
fscanf格式化输入函数所有输入流
fprintf格式化输出函数所有输出流
fread二进制输入文件
fwrite二进制输出文件

解释:上⾯说的适用于所有输入流⼀般指适用于标准输⼊流和其他输⼊流(如文件输⼊流);所有输出流⼀般指适用于标准输出流和其他输出流(如文件输出流)

⚠️:此篇博客都是对当前路径下的test.txt文件进行操作,所以前后会有因果关系

1:fputc

int fputc ( int character, FILE * stream );

参数解释:

参数类型说明
characterint要写入的字符的ascll码值
streamFILE *指向要写入的文件流的指针

注:character也可以直接传递'a'这种字符,因为字符的本质就是ascll码值(int类型)

函数作用:

  • 将字符写入到文件中,成功写入后,文件位置指示器自动向后移动一个字节

返回值:

返回值含义
int (写入的字符的ascll码值)写入成功
EOF(-1)写入失败(读取时到达文件尾或发生错误)

注意事项:

  • fputc作为写函数,自然需要以写相关的打开模式去打开文件

使用示例:

a:写入单个字符

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "w"); if (fp == NULL) { perror("打开文件失败"); return 1; } fputc('A', fp); fclose(fp); return 0; }

解释:

test.txt文件不存在,所以fopen以写的形式打开文件的时候,会先在指定路径下新建该文件,这里的路径只有文件名字,所以默认路径就是当前程序对应的目录

文件如下:

b:循环写入字符

解释:因为是w模式打开文件,而不是追加模式,所以下一次的写之前,会清空上一次所写的内容

2:fgetc

int fgetc ( FILE * stream );

参数解释:

参数类型说明
streamFILE *指向要读取的文件的FILE结构体

函数作用:

  • 从指定的文件流(stream)中读取一个字符

返回值:

  • 返回该字符的 ASCII 值。如果读取时到达文件尾或发生错误,则返回EOF

  • End Of File,一个特殊的常量,通常在大多数系统中定义为 -1

注意事项:

  • 会读取包括空格、换行在内的所有字符

使用示例:

①:读取单个字符

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "r"); if (fp == NULL) { perror("打开文件失败"); return 1; } int ch = fgetc(fp); if (ch != EOF) { printf("读取到的字符:%c\n", ch); } fclose(fp); return 0; }

②:循环读取字符

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "r"); if (fp == NULL) { perror("打开文件失败"); return 1; } int ch; while ((ch = fgetc(fp)) != EOF) { putchar(ch); } fclose(fp); return 0; }

解释:fgetc无法读取时返回值为EOF,所以当我们想循环读取文件的时候,就可以使用返回值不为EOF进行判断,从而循环地去读完整个文件

3:fputs

int fputs ( const char * str, FILE * stream );

参数解释:

参数类型说明
strconst char *要写入的字符串(以\0结尾)
streamFILE *指向要写入的文件流的指针

函数作用:

  • 将字符串写入到指定的文件流中(将字符串str写入到文件流stream中),且文件位置指示器会向后移动写入的字节数

返回值:

返回值含义
>= 0写入成功(返回最后一个写入的非负字符数)
EOF(-1)写入失败

注意事项:

  • fputs不会自动添加换行,需要换行要手动加\n(否则两次fputs会出现在同一行)

  • 字符串必须以\0结尾,否则fputs会一直找字符串中的'\0',可能会导致越界访问

使用示例:

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "w"); if (fp == NULL) { perror("打开文件失败"); return 1; } fputs("hello world", fp); fclose(fp); return 0; }

解释:写入了一个字符串,因为是w方式打开文件,所以之间的文件内容会被清空再写入

4:fgets

char * fgets ( char *str, int num, FILE * stream );

参数解释:

参数类型说明
strchar *字符串的指针,该字符串用于存储读取到的字符串
numint最多读取的字符个数(包含结尾的\0)
streamFILE *指向要读取的文件流的指针

函数作用:

  • 从文件流stream中读取一个最大字符数为(num-1)的字符串str

返回值:

返回值含义
str(传入的指针str)读取成功
NULL到达文件末尾或发生读取错误

注意事项:

  • num参数包含了结尾的\0,所以实际最多读num-1个字符

  • 缓冲区str要足够大,至少num字节

fgets停止读取的三种情况:

情况说明
① 遇到换行符\n读取换行符,将'\n'存入str,然后停止,末尾加\0
② 已读取num-1个字符还没遇到换行符,停止,末尾加\0
③ 遇到文件尾 EOF没有读到任何字符,返回NULL;如果读到部分字符后遇到 EOF,也会停止并加\0

❓️:如果fgets读取的时候遇到了'\0'呢,会提前停止吗?

💡:不会!fgets是把\0当作普通数据字符读取,不会因为读到\0就停止!

验证示例:

我们往文件中写入字符'A' '\0' 'B' '\n' 'C',然后再用fgets读取10个字节

❓️:为什么不用fputs直接写入字符串"A\0B\nC"?

💡:因为fputs写入的时候,遇到\0就会停止,不再往后写入,这是特性,否则fputs停不下来

#include <stdio.h> int main() { // 用 fputs 写入(但 fputs 遇到 \0 会停止写入) FILE* fp = fopen("test.txt", "w"); fputs("A", fp); fputc('\0', fp); // 手动写入 \0 fputs("B\nC", fp); fclose(fp); // 用 fgets 读取 fp = fopen("test.txt", "r"); char buf[100] = { 0 }; fgets(buf, 100, fp); for (int i = 0; i < 10; i++) { printf("buf[%d] = %d\n", i, buf[i]); } fclose(fp); return 0; }

解释:

数组下标十进制值对应字符说明
buf[0]65'A'从文件读取的第一个字符
buf[1]0'\0'从文件读取的空字符(fprintf写入的%c)
buf[2]66'B'\0后面的B,说明遇到\0没停止
buf[3]10'\n'换行符,遇到它fgets才停止读取
buf[4]0'\0'fgets自动添加的字符串结束符
buf[5~9]0'\0'缓冲区剩余空间被初始化为 0(未使用部分)

这代表遇到第一个'\0'没有停止下来,而遇到'\n'换行符才会停止

❓️:为什么要这么设置?

💡:因为文本文件中压根就没有'\0',你在记事本中见过'\0'吗?但是存在换行!所以检测'\n'!!

5:fprintf

int fprintf ( FILE * stream, const char * format, ... );

参数解释:

参数类型说明
streamFILE *指向要写入的文件流的指针
formatconst char *格式控制字符串(包含格式占位符如%d、%s等)
...可变参数对应格式占位符要输出的变量

函数作用:

  • 将格式化的数据写入到指定的文件流中

返回值:

返回值含义
>= 0成功写入的字符总数
负数写入失败

注意事项:

  • 格式字符串与变量类型要匹配,否则结果不可预料

使用示例:

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "w"); if (fp == NULL) { perror("打开文件失败"); return 1; } int age = 25; float score = 92.5; char name[] = "张三"; fprintf(fp, "%s\n", name); fprintf(fp, "%d\n", age); fprintf(fp, "%.1f\n", score); //合成一行的写法 //fprintf(fp, "%s %d %.1f\n", name, age, score); fclose(fp); fp = NULL; return 0; }

解释:说白了就是在printf的用法上,增加一个FILE*类型的参数fp而已

6:fscanf

int fscanf ( FILE * stream, const char * format, ... );

参数解释:

参数类型说明
streamFILE *指向要读取的文件流的指针
formatconst char *格式控制字符串(指定如何解析数据)
...可变参数对应格式占位符的变量地址(用于存储读取的值)

函数作用:

  • 从文件中读取格式化的数据

返回值:

返回值含义
正整数成功匹配并赋值的参数个数
0没有匹配到任何数据(但可能有字符被读取)
EOF(-1)读取时到达文件尾或发生错误

注意事项:

  • 功能与scanf完全相同,区别是scanf从键盘读取,fscanf从文件读取

  • 自动跳过空白字符(空格、换行、制表符等)

  • 遇到类型不匹配或文件尾时停止

使用示例:

#include <stdio.h> int main() { FILE* fp = fopen("test.txt", "r"); if (fp == NULL) { perror("打开文件失败"); return 1; } char name[50]; int age; float score; fscanf(fp, "%s", name); fscanf(fp, "%d", &age); fscanf(fp, "%f", &score); printf("%s\n", name); printf("%d\n", age); printf("%.1f\n", score); fclose(fp); return 0; }

解释:说白了就是在scanf的用法上,增加一个FILE*类型的参数fp而已

7:fwite

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

参数解释:

参数类型说明
ptrconst void *指向要写入的数据的指针
sizesize_t每个元素的大小(字节数)
countsize_t要写入的元素个数
streamFILE *指向要写入的文件流的指针

函数作用:

  • 将数据块以二进制的形式写入文件流(fwrite从由ptr指向的内存块中取出count个元素,每个元素的大小为size字节,并将它们写入到stream指向的文件流中)

返回值:

返回值含义
count成功写入的元素个数(等于count表示全部成功)
< count部分写入成功(通常表示磁盘满或发生错误)

注意事项:

  • 文件通常以二进制模式打开("wb"、"ab"、"wb+")

  • 写入的是原始二进制数据,用记事本打开可能显示乱码

  • 返回的是元素个数,不是字节数(实际字节数 = 返回值 × size)

  • 适合配合fread使用

使用示例:

#include <stdio.h> int main() { FILE *fp = fopen("test.txt", "wb"); if (fp == NULL) { perror("打开文件失败"); return 1; } int arr[] = {10, 20, 30, 40, 50}; fwrite(arr, sizeof(int), 5, fp); fclose(fp); return 0; }

解释:fwrite以二进制的形式向test.txt文件中写入数据后,我们此时打开test.txt文件就是乱码

8:fread

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

参数解释:

参数类型说明
ptrvoid *指向存储读取数据的缓冲区的指针
sizesize_t每个元素的大小(字节数)
countsize_t要读取的元素个数
streamFILE *指向要读取的文件流的指针

函数作用:

  • 从文件中以二进制形式读取数据到内存中

  • 适合读取数组、结构体等二进制数据

  • 文件位置指示器向后移动size × 实际读取的元素个数字节

返回值:

返回值含义
count成功读取的元素个数(等于count表示全部成功)
< count部分读取成功(可能到达文件尾或发生错误)
0

没有读取到任何元素(文件尾或错误)

注意事项:

  • 文件通常以二进制模式打开("rb"、"ab"、"rb+")

  • 读取的是原始二进制数据,必须与写入时的格式完全一致

  • 缓冲区ptr必须足够大,至少size × count字节

  • 适合配合fwrite使用

使用示例:

#include <stdio.h> int main() { // 先写入数据 FILE* fp = fopen("test.txt", "wb"); int arr1[] = { 10, 20, 30, 40, 50 }; fwrite(arr1, sizeof(int), 5, fp); fclose(fp); // 再读取数据 fp = fopen("test.txt", "rb"); int arr2[5]; fread(arr2, sizeof(int), 5, fp); for (int i = 0; i < 5; i++) { printf("%d ", arr2[i]); } fclose(fp); return 0; }

📌 [ 作者 ] shylyly
📃 [ 首次发布 ] 2024.3.28
❌ [ 最新修改 ] 2026.10.14
📜 [ 声明 ] 由于笔者水平有限,文中难免有疏漏或不妥之处,还望读者不吝赐教

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询