#C语言——学习攻略:攻克 文件操作内容(二),根本不在话下!

🌟菜鸟主页:@晨非辰的主页

👀学习专栏:《C语言学习》

💪学习阶段:C语言方向初学者

名言欣赏:“人理解迭代,神理解递归。”


目录

4.  文件的顺序读写(续)

4.6  fprintf 函数

4.7  fscanf 函数

4.8  fwrite 函数

4.9  fread 函数

5.  sprintf 、sscanf函数

5.1  相似函数对比

5.2  sprintf函数

5.3  sscanf函数

6. 文件的随机读写

6.1  fseek函数

6.2  ftell函数

6.3  rewind函数

7.  文件缓冲区

7.1  fflush函数

8.  更新文件


4.  文件的顺序读写(续)

4.6  fprintf 函数

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

功能:将格式化数据写入指定文件流,与 printf 类似,但可以输出到任意文件(如磁盘文件、标准输出、标准错误等),不限于控制台;

参数:

        --stream :指向 FILE 对象的指针,表示要写入的文件流( stdout 、文件指针等);

        --format :格式化字符串,含要写入的文本和格式说明符(如 %d 、 %s 等);

        --... :可变参数列表,提供与格式字符串中说明符对应的数据;

返回值:--成功,返回写入的字符总数(非负值); --失败,先设置对应流的错误指示器,再返回负值,可以通过 ferror() 来检测。

struct stu
{
	char name[30];
	int age;
	float score;
};
int main()
{
	struct stu s = { "zhangsan",18,95.5f };
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fprintf(fp, "%s %d %f", s.name, s.age, s.score);

	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

--将文件输出流换成标准输出流,就和printf一样输出到屏幕

4.7  fscanf 函数

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

功能:从指定文件流中读取格式化数据。类似 scanf ,但可以指定输入源(如文件、标准输入等),不·限于控制台输入。适用于从文件解析结构化数据(如整数、浮点数、字符串等);

参数:

        --stream :指针,表示要读取的文件流(如 stdin 、文件指针等);

        --format :格式化字符串,定义如何解析输入数据(如 %d 、 %f 、 %s 等);

        --... :可变参数列表,提供存储数据的变量地址(需与格式字符串中的说明符匹配);

返回值:

--成功,函数返回成功填充到参数列表中的项数。该值可能与预期项数⼀致,或因以下原因少于预期(甚至为零):

  • 格式和数据匹配失败;
  • 读取发生错误;
  • 到达文件末尾(EOF)。

-成功读取任何数据之前发生:

  • 发生读取错误,在对应流上设置错误指示符,返回 EOF ;
  • 到达文件末尾,在对应流上设置文件结束指示符,返回 EOF ;
--在上一函数相关代码运行基础上
struct stu
{
	char name[30];
	int age;
	float score;
};
int main()
{
	struct stu s = { 0 };
	FILE* fp = fopen("data.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fscanf(fp, "%s %d %f", s.name, &(s.age), &(s.score));
	fprintf(stdout, "%s %d %f", s.name, s.age, s.score);
	//打印数据在stdout

	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

4.8  fwrite 函数

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

功能:将数据从内存缓冲区写入到文件,二进制写入;

参数:

        --ptr:指向内存缓冲区的指针,缓冲区包含要写入文件的数据;

        --size:要写入的每个数据元素的大小(字节单位);

        --count:要写入数据元素的个数;

        --stream:指向 FILE 类型结构体的指针,指定要写入数据的文件流。

返回值:

        --成功:返回成功写入的数据元素个数;

        --失败:发生写入错误或到达文件尾,返回值会小于count(feof()ferror()函数判断)。

--注意:

包含 <stdio.h> 头文件;

使用fwrite() 之前,确保文件以二进制可写方式打开;

fwrite() 通常用于⼆进制数据的写入,如果写入文本数据,请谨慎处理换行符和编码等问题。

--下面以结构体演示:

struct S
{
	char name[20];
	int age;
	float score;
};


int main()
{
	struct S s = { "zhangsan", 20, 95.5 };
	FILE*pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	if (fwrite(&s, sizeof(struct S), 1, pf) != 1)
	{
		perror("fwrite");
		return -1;
	}

	fclose(pf);
	pf = NULL;

	return 0;
}


4.9  fread 函数

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

功能:从 stream 指向的文件流中读取数据块,并将其存储到 ptr 指向的内存缓冲区中;

参数:

        --ptr :指向内存区域的指针,用于存储从文件中读取的数据;

        --size :读取的每个数据块的大小(字节单位);

        --count :要读取的数据块的数量;

        --stream :指向 FILE 类型结构体的指针,指定了要从中读取数据的文件流。

返回值:实际读取的数据块数量。

--注意:

包含 <stdio.h> 头文件;

使用fread() 之前,确保文件已经以二进制可读方式打开;

ptr 指向的内存区域必须足够大,以便存储指定数量和大小的数据块;

fread() 成功读取了指定数量的数据块,返回值等于 count ;读取数量少于count ,可能到达文件结尾或发生错误;

二进制文件读取, fread() 是常用的函数;对于文本文件读取,使用 fgets()或 fscanf()。

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	FILE* ps = fopen("data.txt", "rb");
	if (ps == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	struct S s = { 0 };
	if (fread(&s, sizeof(struct S), 1, ps) != 1)
	{
		if (feof(ps))
		{
			printf("遇到了文件末尾\n");
		}
		else if (ferror(ps))
		{
			printf("读取错误");
		}
	}
	else
	{
		printf("%s %d %f", s.name, s.age, s.score);
	}

	//关闭文件
	fclose(ps);
	ps == NULL;
	return 0;
}

--fread 函数与 fwrite 函数的参数作用正好相反,fread 函数是将从data.txt文件中读取到的结构体数据(fwrite函数写入的),存到一个空结构体中。


5.  sprintf 、sscanf函数

5.1  相似函数对比

scanf

针对标准输入(stdin)的格式化输入函数
printf针对标准输出(stdout)的格式化输出函数
fscanf针对所有输入流(文件流,stdin)的格式化输入函数
fprintf针对所有输出流(文件流,stdout)的格式化输出函数
sprintf将格式化的数据转换成字符串
sscanf从字符串中提取格式化的数据

5.2  sprintf函数

int sprintf(char* str, const char* format, ...);

功能:将格式化数据写入字符数组(字符串)。类似 printf ,但输出目标是用户指定的内存缓冲区。用于动态生成字符串、拼接数据或转换数据格式;(格式化的数据转换为字符串)

参数:

        --str:指向字符数组,存储生成的字符串(确保空间够大);

        --formate:格式化字符串,定义输出格式(如 %d 、 %f 、 %s 等);

        --... :可变参数列表,提供与格式字符串中格式符对应的数据。

返回值:

        --成功:写入缓存区的字符数(不包括结尾的空字符 \0 );

        --失败;返回负值。

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhaoxiehao",18,85.5f };
	char buf[200] = { 0 };
	sprintf(buf, "%s %f %d", s.name, s.score, s.age);
	printf("%s", buf);//按照指定的格式打印成字符串形式
	return 0;
}

5.3  sscanf函数

 int sscanf(const char* str, const char* format, ...);

功能:从字符串中读取格式化数据。与 scanf 类似,但输入源是内存中的字符串。常用于解析字符串中的结构化数据(如提取数字、分割文本等);

参数:

        --str:要解析的字符串;

        --formate:格式化字符串,定义解析格式(如 %d 、 %f 、 %s 等);

        --... :可变参数列表,提供存储数据的变量地址(与格式字符串中的格式符匹配)。

返回值:

        --成功:返回成功解析并赋值的参数数量(非负值);

        --失败或未匹配任何数据:输入结束或解析失败,返回 EOF (通常是 -1 


6. 文件的随机读写

6.1  fseek函数

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

功能:根据文件指针的位置和偏移量来定位指针;

参数:

        --stream:指向 FILE 类型结构体,指定了要操作的文件流;

        --offset:表示偏移量(字节单位)。指定了从origin指定位置开始,文件指针要移动的距离(正负数、0);

        --origin:指定偏移量起始位置,整数常量,三种取值情况:


  1. SEEK_SET:文件开头,offset表示从文件开头开始的偏移量;
  2. SEEK_CUR:当前文件指针位置,offset是相对于当前位置(光标位置)的偏移量;
  3. SEEK_END:文件末尾,offset从文件末尾开始的偏移量,为负数用于倒着定位文件指针。

返回值:成功--0;失败--非0(设置errno表示错误类型)

#include<stdio.h>
//先另创建文本文件,内容abcdefghi
int main()
{
	FILE* ps = fopen("data1.txt", "r");
	if (ps == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch = fgetc(ps);
	printf("%c\n", ch);//打印a

	//打印g
	fseek(ps, 5, SEEK_CUR);
	//fgetc函数读取'a',光标向后移到'a'后
	//偏移量是5,来到'g'前

	ch = fgetc(ps);
	printf("%c\n", ch);//g

	//关闭文件
	fclose(ps);
	ps = NULL;
	return 0;
}
#include<stdio.h>
int main()
{
	FILE* ps = fopen("data1.txt", "w");
	if (ps == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputs("abcdefghi", ps);

	//把g修改成x,fputs写完后光标在最后 
	fseek(ps, -3, SEEK_END);
	fputc('x', ps);//写'x'

	//关闭文件
	fclose(ps);
	ps = NULL;
	return 0;
}


6.2  ftell函数

long int ftell ( FILE * stream );

--介绍

功能:返回文件指针相对于文件起始位置的偏移量;

参数: stream--指向 FILE 类型结构体的指针,指定要操作的文件流,来获取该文件当前的指针位置;

返回值:--成功,返回文件指针相对于文件开头的字节数;v --失败,返回-1L,并设置errno来指示错误类型。

#include<stdio.h>
int main()
{
	FILE* ps = fopen("data.txt", "w");
	if (ps == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputs("abcdefghi", ps);

	//g修改成x,写完后光标在最后 
	fseek(ps, -3, SEEK_END);
	fputc('x', ps);

	//光标来到末尾,算相对起始位置的偏移量
	fseek(ps, 0, SEEK_END);

	//此时光标在末尾,距离于文件开头由有9个字符--9字节
	int c = ftell(ps);
	printf("%d", c);
	//关闭文件
	fclose(ps);
	ps = NULL;
	return 0;
}

6.3  rewind函数

 void rewind(FILE* stream );

功能:让文件指针(光标)的位置回到文件起始位置,——>fseek(ps, 0, SEEK_SET);

参数:stream--指向 FILE 类型结构体,指定要操作的文件流,通过参数,rewind 函数能够知道对哪个文件进行操作,将该文件文件指针移至文件开头。

#include<stdio.h>
int main()
{
	FILE* ps = fopen("data1.txt", "w");
	if (ps == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputs("abcdefghi", ps);

	//g修改成x ,光标在末尾
	fseek(ps, -3, SEEK_END);
	fputc('x', ps);

	//光标来到末尾,算相对文件开头的偏移量
	fseek(ps, 0, SEEK_END);
	int c = ftell(ps);
	printf("%d", c);

	//让文件指针到文件起始位置,把a改成q;
	rewind(ps);
	fputc('q', ps);
	//关闭文件
	fclose(ps);
	ps = NULL;
	return 0;
}


7.  文件缓冲区

--ANSI C 标准采用“缓冲文件系统” 处理数据文件,缓冲文件系统是系统自动在内存中为程序每个正使用的文件开辟“文件缓冲区”。从内存向磁盘输出数据先到内存的缓冲区,装满缓冲区后⼀起送到磁盘。若从磁盘向计算机读⼊数据,从磁盘文件中读取数据输入内存缓冲区(充满缓冲区),再从缓冲区逐个将数据送到程序数据区(程序变量等)。缓冲区大小根据C编译系统决定的。

7.1  fflush函数

int fflush(FILE* stream); 

功能:强制刷新参数 stream 指定流的缓冲区,确保数据写入底层设备;

  • 输出流:将缓冲区中未写入的数据立即写入文件;
  • 输入流:行为由具体实现决定,非C语言标准行为(可能清空输入缓冲区);
  • 参数为 NULL :刷新所有打开的输出流;

参数:stream--指向文件流(stdout 、文件指针等);

返回值:成功返回 0 ,失败返回 EOF;--

--注意

仅对输出流更新流(最后⼀次操作为输出)有明确刷新行为;

输入流的刷新行为不可移植(如清空输入缓冲区是非标准特性);

程序正常终止( exit )或调用 fclose 时会自动刷新,但程序崩溃时缓冲区数据可能丢失。

#include <stdio.h>
#include <windows.h>

int main()
{
    FILE* pf = fopen("test.txt", "w");
    fputs("abcdef", pf);//先将代码放在输出缓冲区
    printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
    Sleep(10000);
    printf("刷新缓冲区\n");
    fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)

    //注:fflush 在高版本VS上不能使用了
    printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
    Sleep(10000);
    fclose(pf);

    //注:fclose在关闭文件的时候,也会刷新缓冲区
    pf = NULL;
    return 0;
}

 这里可以得出一个结论:因为存在缓冲区,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件,如果不做,可能导致读写文件的问题。


8.  更新文件

行为"r+""w+""a+"
解释可读/可写可读/可写可读/可写
文件不存在打开失败创建文件创建文件
文件存在保留内容清空保留
初始文件指针位置文件开头开头末尾
写入是否覆盖数据是(可定位覆盖)是(内容清空,从头写)否(默认在末尾写数据)
用途修改文件部分内容创建新文件/重写旧文件在文件末尾追加数据--记录日志

注意:

--写完文件后,要继续读文件时,读取前一定使用fflush()刷新缓冲区,或使用fseek()、rewind()重新定位文件指示器位置;

--读完文件后,需要继续写文件前,用fseek()、rewind()重新定位文件指示器的位置。


相关系列回顾:

#C语言——学习攻略:攻克 动态内存分配、柔性数组,根本不在话下!

#C语言——学习攻略:攻克 文件操作内容(一),根本不在话下!

结语:本篇文章到此结束,对于C语言相关知识大家要多次回顾,如果这篇文章对你的学习有帮助的话,欢迎一起讨论学习,你这么帅、这么美给个三连吧~~~

评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值