当前位置: 首页 > news >正文

C语言常见的文件操作函数总结

目录

前言

一、打开和关闭

1.fopen

细节

2.fclos

基本用法示例

二、读写

1.fputc和fgetc

1)fputc

细节

基本用法示例

2)fgetc

细节

基本用法示例

2.fputs和fgets

1)fputs

细节

基本用法示例

2)fgets

细节

基本用法示例

3)puts的使用,以及为什么不推荐使用gets

基本用法示例

不推荐使用gets的原因

3.fscanf和fprintf

1)fscanf

细节:

fscanf和scanf的区别与联系

基本用法示例

补充

2)fprintf

细节

基本用法示例

4.sprintf和sscanf

1)sprintf

细节

基本用法示例

2)sscanf

细节

基本用法示例

总结



前言

以下函数均在头文件"stdio.h"中。


一、打开和关闭

1.fopen

fopen(),这个函数很简单,也不容易忘。两个参数一是文件名或者路径,二是打开方式。

如果文件就在当前路径下的话,那直接输入“文件名”即可,记得用双引号。如果不是当前路径,那就把目标的路径输进去。如下图:

(什么是当前路径?就是你创建源文件.c或者.cpp的那个文件夹)

打开当前路径下文件的方式:

打开其他路径下文件的方式:

这里列出常用的,注意打开方式也要用双引号括起来

细节

上述参数带不带加号有什么区别呢?带 + 的模式支持读写:

一句话总结

带 +:允许读写,但不同模式对文件处理方式不同(r+保留内容,w+清空内容,a+强制末尾追加)。

不带 +:只能读或写,功能单一,部分模式会清空文件(如 w)。

一打开文件后都要测试一些打开成功没,防止野指针操作

FILE * P;
//方法一
assert(P);
//方法二
if(!P)
{printf("FILE ERROR");return 1;
}

常用的如assert(P);这个函数的作用是检查括号内的值是否为真,否则就报错停止程序。但需要包上“assert.h”头文件。

当然if(!P)也是简单好用,如果打开文件失败,则P为NULL,!P就为真。

2.fclos

fclos( ),这个很简单,直接将指针放进去就好了,如fclos(P),一般是不会失败的

基本用法示例

#include<stdio.h>
#include<assert.h>int main()
{FILE* w = fopen("log.txt", "w");assert(w);//检查w是否为空。如果为空则打印错误并停止运行//你的过程fclose(w);return 0;
}

二、读写

1.fputc和fgetc

1)fputc

作用:向stream,目标文件流 写入单个字符。

参数有个,一是int char,即要写入的字符,二是要写入文件的指针

fputc写入成功时返回写入的字符的ASCII码,失败时返回EOF。

ASCII_百度百科

细节

由于fputc接受int型参数,故当把char类型传入时,其实发生了隐形的转换,也就是从char型转换为int型(该字符所对应的ASCII码)。

至于为什么将fgetc的参数设置为int型有以下几个原因:
①兼容与文件相关EOF,EOF为文件结束的标志,通常定义为-1;

char 类型在不同平台上的符号性可能不同,使用 int 类型可以绕过符号性问题,确保所有 0 到 255 的字符值都能正确传递。

③整数提升规则:在 C 语言中,当 char 类型作为参数传递给函数时,会自动提升为 int 类型。

基本用法示例

void test1w()
{FILE* w = fopen("log.txt", "w");assert(w);char* str = "hello ,this is a test\n";char* tem = str;for (int i = 5; i > 0; --i){while (*str != '\0')fputc(*str++, w);str = tem;}//printf("%s\n", str);fclose(w);
}

结果:

2)fgetc

作用:从文件、字符串或其他中读单字符。

函数参数就一个stream,目标文件流 文件指针。

读取成功返回该字符的ASCII码(int),失败则EOF,当读取到文件末尾返回EOF(-1),fgetc一般配合循环使用。

细节

①在从文件读取时判断结束的条件是EOF,但从字符串读取时,判断条件则为'\0'(字符串默认以'\0'结尾);

注意缓冲区溢出问题,如下方示例中以char [200]数组sbuffer接受读取到的字符,接受的字符不能大于等于num(这里即199)——因为字符串默认以'\0'结尾,所以这里还要我们手动添加\0

如果事先不知道文件中有多少字符,该如何设置缓冲区大小?

①可以用动态增容数组——malloc和realloc;

②可以循环打印,比如当缓冲区快满时,将缓冲区打印或者放到其他什么容器里吗,然后将下标置为0。

基本用法示例

void test1r()
{FILE* r = fopen("log.txt", "r");assert(r);char sbuffer[200];int t;int i = 0;while ((t=fgetc(r))!=EOF){sbuffer[i++] = (char)t;if (i == sizeof(sbuffer) - 1)break;}sbuffer[i] = '\0';printf("%s", sbuffer);fclose(r);
}

结果:

2.fputs和fgets

1)fputs

作用:写入字符串到文件或其他,按行写入。

参数:str,待写入的字符串(需以 \0 结尾)。stream,目标文件流 文件指针或stdout

返回值:成功返回非负整数,失败返回EOF。

细节

①fputs 不会自动添加换行符,如:

fputs("Line 1", fp); fputs("Line 2", fp);

文件写入的实际内容为Line 1Line 2。需要手动添加,如fputs("Line 1\n", fp)。

②fputs不会检查字符串是否以\0结尾,如果传入的字符串没有 \0 结尾,可能导致缓冲区溢出或写入乱码。需要手动添加\0,如char str[] = { 'h','h','h' ,'\0'};

基本用法示例

void test2w()
{FILE* w = fopen("log.txt", "w");assert(w);char str[] = "hello\nworld\nC&C++\n";printf("%d", fputs(str, w));fclose(w);
}

结果:

2)fgets

作用:从文件或其他读取num-1个字符串到str缓冲区中。

参数:str,用于存储读取数据的字符数组(缓冲区);num,要读取的最大字符数;stream,输入流如 stdin 或文件指针。

返回值:成功返回str指针,失败返回NULL。

细节

1)fgets遇到以下情况会停止读取:

①读取了num-1个字符;

②遇到了换行符;

如果文件或者字符串中有很多\n应该怎么读完呢?——循环读取如下示例

③到达文件末尾 (EOF)。

2)读取的字符串会以 \0 结尾

3)为什么读取num-1个字符?因为要给\0留一个

如果事先不知道文件中有多少字符,该如何设置缓冲区大小?

①可以用动态增容数组——malloc和realloc;

②可以循环打印,比如当缓冲区快满时,将缓冲区打印或者放到其他什么容器里吗,然后将下标置为0。

基本用法示例

void test2r()
{FILE* r = fopen("log.txt", "r");assert(r);char s[100];char str[100];int total = 0;while (fgets(s, 100, r) != NULL && total + strlen(s) < 100){strcpy(str+total, s);total += strlen(s);}printf("%s", str);fclose(r);
}

结果

3)puts的使用,以及为什么不推荐使用gets

作用:将字符串 str 输出到标准输出(通常是屏幕),并自动追加换行符 \n。

返回值成功时返回非负值(通常是输出的字符数,包括换行符),失败返回 EOF

细节

传入的指针必须指向以 \0 结尾的字符串,否则会导致未定义行为(如输出乱码)。

基本用法示例

char str[] = "Hello World";
puts(str);       // 输出 "Hello World" 并换行

不推荐使用gets的原因

缓冲区溢出风险。fgets相比,gets并没有指定读取多少字符,有缓冲区溢出的风险。

如:

char buffer[5];
gets(buffer); // 输入 "123456" 时,buffer 溢出(仅能容纳4字符+1个\0)

由上述原因,从C11标准开始gets 被正式从C语言标准库中移除。若使用gets函数,编译器会给出警告,并推荐使用fges。

3.fscanf和fprintf

1)fscanf

首先明确的是fscanf与scanf非常相似,故使用方法上也会有相似之处。

作用:从文件读取格式化输入,即从文件中读取数据。

参数:stream,输入文件流(如 FILE *p);format,格式化字符串(与 scanf 格式相同,类似于scanf的第一个参数);…表示format可以有多个。

返回值:成功,返回成功匹配和赋值的参数个数。失败或到文件尾返回EOF。

细节:

①fscanf与scanf类似都是从文件流中读取数值到某个容器中,故读取顺序不能更改否则类型不匹配;

②若用fscanf读取字符串,则需要留一位给\0,比如字符数组20,则只能读19——%19s;

fscanf和scanf的区别与联系

①fscanf可以从任意文件流中读取,而scanf只能从stdin标准输入流中读取;

②fscanf需要检查文件指针是否有效;

③scanf是fscanf的特例——fscanf(stdin,……);

基本用法示例

void test3r()
{FILE* r = fopen("log.txt", "r");int date, dat, ret;char name[2][20];ret=fscanf(r, "%19s %d %d %19s", &name[0], &date, &dat,&name[1]);if (ret == 4)printf("ret=%d, %d %d\n %s %s", ret, date, dat, name[0], name[1]);elseprintf("fscanf读取有误,匹配到:%d\n", ret);fclose(r);
}

补充

一些方便的格式:

%[^ x]:读取直到遇到x代表的符号,如%[ ^ ,]读取直到遇到' , ';

%*d:跳过整数。

2)fprintf

作用:从文件写入格式化输出,即从文件中写入数据。

参数:stream,目标文件流(如文件指针或 stdout/stderr);format,format,格式化字符串(与 printf格式相同);…表示format可以有多个。

返回值:成功,返回写入的字符数。失败返回负数

细节

①参数类型要匹配,即写入顺序不能更改;

②与fscanf不同的是,fprintf是朝文件写入,若只是写入字符串则可以不用加上后面的变量,如:

fprintf(p, "Hello World");//将字符串写入文件P;

fprintf 可指定输出目标,printf 固定输出到 stdout。

基本用法示例

void test3w()
{FILE* w = fopen("log.txt", "w");assert(w);char name[15] = "zhangsan";int date1 = 1, date2 = 2, date3 = 3;fprintf(w, "%s %d %d \n", name, date1, date2);fprintf(w, "hello\nsee you");fclose(w);
}

结果

4.sprintf和sscanf

1)sprintf

作用:sprintf 用于字符串格式化输入将变量中的数据输入到字符串中,功能类似 printf ,但操作对象是字符串而非标准输入输出流。

参数:str,目标字符串(缓冲区);format,format,格式化字符串(与 printf格式相同);…表示format可以有多个。

返回值:成功写入的字符数,失败返回负数。

细节

①sprintf会自动为字符数组尾添加\0;

②sprintf 不会检查目标字符串 str 的长度,需手动确保足够空间。

③sprintf 支持printf的所有格式;

基本用法示例

void test4w()
{char bufer[64];double pi = 3.1415926;int day = 20250510;char str[] = "hello sprintf";sprintf(bufer, "pi=%.7f,day=%d,str=%s", pi, day, str);printf("%s", bufer);
}

结果

2)sscanf

作用:sprintf 用于字符串格式化输出,从字符串解析数据,功能类似scanf,但操作对象是字符串而非标准输入输出流。

参数:s,目标字符串(缓冲区);format,format,格式化字符串(与 printf格式相同);…表示format可以有多个。

返回值成功匹配并赋值的参数个数,失败返回 EOF

细节

①可以用" * "跳过忽略选项,这个可以用来提取字符串中指定的数据

如:

char *str="total 5 $";

int num;

sscanf(str, "%*s %d", &num); // %*s 跳过 "total",然后读取 5

②用%[a-z]匹配小写字符串,用%[A-Z]匹配大写字符串;

如:

    int ret=sscanf("ABC,abc,A", "%[A-Z],%[a-z],%c", a, b, &c);
    printf("%s\n%s\n%c", a, b, c);

③%[^ 内容],意思是只匹配字符串中符合内容中的值

如:

sscanf(str, "%*[^0-9]%d", &num);  // 跳过所有非数字字符,直到遇到数字

char str[20];
sscanf("hello,world", "%[^,]", str); // str="hello"

④%n 记录已读取的字符数

如:

int pos;
sscanf("12345", "%d%n", &num, &pos); // num=12345, pos=5

⑤使用宽度限定符防止溢出

如:

char name[10];
sscanf("abcdefghijklmn", "%9s", name); // 只读前9字符

基本用法示例

void test4r()
{char str[] = "2025/5/10";int year, mon, day;char a[10], b[10], c;int ret = sscanf(str, "%d/%d/%d", &year, &mon, &day);printf("%d/%d/%d\n", year, mon, day);sscanf("ABC,abc,A", "%[A-Z],%[a-z],%c", a, b, &c);printf("%s\n%s\n%c", a, b, c);
}

输出:


总结

本文总结了有关文件操作的一些常用的函数。由于在日常较少使用这些函数,每每想用又不免查找,因此有了这篇文章。

希望对你有所帮助。

读完点赞,手留余香~

相关文章:

  • QSS样式表的选择器
  • iVX 图形化编程平台:结合 AI 原生开发的革新与实践
  • 模块化编程
  • 【问题】Watt加速github访问速度:好用[特殊字符]
  • ACM模式手动构建二叉树
  • 精读计算机体系结构基础 第三章 特权指令系统
  • 使用 SHAP 进行特征交互检测:揭示变量之间的复杂依赖关系
  • 豆包:国内 web 辅助开发的领头羊
  • 以党建网为例,深入分析IT技术栈,实战经验
  • 基于多层权重博弈与广播机制的仿生类脑 AI 决策框架
  • 文件(分片)并行上传时计算总的上传进度
  • Linux基础开发工具一(yum/apt ,vim)
  • C++内存管理详解
  • ES 面试题系列「二」
  • HTML难点小记:一些简单标签的使用逻辑和实用化
  • 49.EFT测试与静电测试环境和干扰特征分析
  • RS485和RS232 通信配置
  • 【Linux高级全栈开发】2.1高性能网络-网络编程——2.1.1 网络IO与IO多路复用——select/poll/epoll
  • Kubernetes排错(十四):Pod状态异常排查手册
  • 每日脚本 5.11 - 进制转换和ascii字符
  • 全国重点网络媒体和网络达人走进沧州,探寻“文武双全”的多重魅力
  • 兵韬志略|美2026国防预算未达1万亿,但仍寻求“暗度陈仓”
  • 马云再次现身阿里打卡创业公寓“湖畔小屋”,鼓励员工坚持创业精神
  • 19个剧团15台演出,上海民营院团尝试文旅融合新探索
  • 国家主席习近平同普京总统出席签字和合作文本交换仪式
  • 外交部:中欧关系50年发展最宝贵经验是相互尊重,求同存异