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

发布于:2025-05-12 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

前言

一、打开和关闭

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]);
	else
		printf("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);
}

输出:


总结

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

希望对你有所帮助。

读完点赞,手留余香~


网站公告

今日签到

点亮在社区的每一天
去签到