c语言笔记第三部分

记录一下c语言的学习过程,笔记如有错误,欢迎指出!!!

文章目录

  • 11.文件
    • 1.系统文件:
    • 2.文件指针和普通指针区别:
    • 3.文件分类:
    • 4.文件操作一般步骤:
      • 1.打开、关闭文件函数:
      • 2.文件访问路径:
      • 3.按字符写文件 fputc:
      • 4.按字符读文件 fgetc
      • 5.feof()函数:
      • 6.fgets()函数:
      • 7.fputs()函数:
      • 8.fwrite()函数:
      • 9. fread()函数:
      • 8.练习: 获取用户键盘输入,写入文件。
      • 9.练习: 文件版四则运算:
      • 10.fprintf()函数:
      • 11.fscanf()函数:
      • 按随机位置读写
      • 12.练习:文件版排序
          • 1.fwrite()函数:
        • 2.fread()函数:
      • 13. 练习:大文件拷贝
        • 1.fseek(),ftell()
      • 14.Linux和windows文件区别:
      • 15.获取文件状态:
      • 16. 删除、重命名文件:
      • 17. 缓冲区刷新:

11.文件

读写文件与printf、scanf关联

printf -- 屏幕 -- 标准输出

scanf -- 键盘 -- 标准输入

perror -- 屏幕 -- 标准错误

1.系统文件:

标准输入 -- stdin -- 0

标准输出 -- stdout -- 1

标准错误 -- stderr -- 2

应用程序启动时,自动被打开,程序执行结束时,自动被关闭。 ---- 隐式回收。

1s = 1000ms 

1ms = 1000us

1us == 1000ns

2.文件指针和普通指针区别:

FILE *fp = NULL;

借助文件操作函数来改变 fp 为空、野指针的状况。	fopen();  --> 相当于 fp = malloc();

操作文件, 使用文件读写函数来完成。 fputc、fgetc(按字符)、fputs、fgets(按行)、fread、fwrite(按块)、fscanf, fprintf(按格式化读写,遇到空格,换行,制表符停止)
// windows中文本方式打开文件,换行为\r\n  Linux中文本方式打开文件,换行为\n,  两种系统用二进制方式打开文件,换行都是\n

3.文件分类:

设备文件:

	屏幕、键盘、磁盘、网卡、声卡、显卡、扬声器...

磁盘文件:

	文本文件: 	ASCII

	二进制文件:	0101 二进制编码

4.文件操作一般步骤:

1. 打开文件 fopen()  --》 FILE *fp;

2. 读写文件 fputc、fgetc、fputs、fgets、fread、fwrite

3. 关闭文件 fclose()  // 可以刷新文件缓冲区

1.打开、关闭文件函数:

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

	参1:待打开文件的文件名(访问路径)

	参2:文件打开权限:

		"r": 只读方式打开文件, 文件不存在,报错。存在,以只读方式打开。

		"w": 只写方式打开文件, 文件不存在,创建一个空文件。文件如果存在,清空并打开。

		"w+":读、写方式打开文件,文件不存在,创建一个空文件。文件如果存在,清空并打开。

		"r+":读、写方式打开文件, 文件不存在,报错。存在,以读写方式打开。

		"a": 以追加的方式打开文件。

		"b": 操作的文件是一个二进制文件(Windows)

	返回值:成功:返回打开文件的文件指针

		失败:NULL


int fclose(FILE * stream);

	参1:打开文件的fp(fopen的返回值)

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

2.文件访问路径:

绝对路径:

	从系统磁盘的 根盘符开始,找到待访问的文件路径

	Windows书写方法:

		1)C:\\Users\\afei\\Desktop\\06-文件分类.avi

		2)C:/Users/afei/Desktop/06-文件分类.avi  --- 也使用于Linux。

相对路径:

	1)如果在VS环境下,编译执行(Ctrl+F5),文件相对路径是指相对于 day10.vcxproj 所在目录位置。

	2)如果是双击 xxx.exe 文件执行,文件的相对路径是相对于 xxx.exe 所在目录位置。 

3.按字符写文件 fputc:

int fputc(int ch, FILE * stream);

	参1:待写入的 字符

	参2:打开文件的fp(fopen的返回值)

	返回值: 成功: 写入文件中的字符对应的ASCII码

		 失败: -1

4.按字符读文件 fgetc

int fgetc(FILE * stream);

	参1:待读取的文件fp(fopen的返回值)

	返回值: 成功:读到的字符对应的ASCII码

		 失败: -1
	fgetc会读出eof,表现为空格

文本文件的结束标记: EOF ---》 -1 

5.feof()函数:

int feof(FILE * stream);

	参1: fopen的返回值

	返回值: 到达文件结尾--》非0【真】
			
		 没到达文件结尾--》0【假】

作用:	
	用来判断到达文件结尾。 既可以判断文本文件。也可以判断 二进制文件。

特性:

	要想使用feof()检测文件结束标记,必须在该函数调用之前,使用读文件函数。

	feof()调用之前,必须有读文件函数调用。

6.fgets()函数:

获取一个字符串, 以\n作为结束标记。自动添加 \0. 空间足够大 读\n, 空间不足舍弃\n, 必须有\0。

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

	char buf[10];  	hello --> hello\n\0

	返回值: 成功: 读到的字符串

		 失败: NULL

7.fputs()函数:

写出一个字符串,如果字符串中没有\n, 不会写\n。

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

	返回值: 成功: 0

		 失败: -1
		 // 

8.fwrite()函数:

写出数据到文件中。
既可处理以文本文件。也处理二进制文件。
stu_t stu[4] = { ...... };

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

	参1:待写出的数据的地址

	参2:待写出数据的大小

	参3:写出的个数				-- 参2 x 参3 = 写出数据的总大小。

	参4:文件

	返回值: 成功:永远是 参3 的值。 --- 通常将参2 传 1. 将参3传实际写出字节数。

		 失败:0 

9. fread()函数:

从文件fp中读出数据。

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

	参1:读取到的数据存储的位置

	参2:一次读取的字节数

	参3:读取的次数				-- 参2 x 参3 = 读出数据的总大小

	参4:文件

	返回值: 成功:参数3.	--- 通常将参2 传 1. 将参3传欲读出的字节数。				

		 0:读失败 -- 到达文件结尾 -- feof(fp)为真。

按块读写

fread()和fwrite()可以按块读写文件

struct Hero
{
	char name[64];     // 如果属性开辟到堆区,不要存指针到文件中,要将指针指向的内容存放到文件中
	int age;
};



//写文件  wb二进制方式
	FILE * f_write = fopen("./test03.txt", "wb");
	if (f_write == NULL)
	{
		return;
	}

	struct Hero heros[4] = 
	{
		{ "亚瑟" , 18 },
		{ "赵云", 28 },
		{ "妲己", 19 },
		{ "孙悟空", 99 },
	};

	for (int i = 0; i < 4;i++)
	{
		//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
		fwrite(&heros[i], sizeof(struct Hero), 1, f_write);
	}

	fclose(f_write);

	//读文件  
	FILE * f_read = fopen("./test03.txt", "rb");  // read binary
	if (f_read == NULL)
	{
		return;
	}

	struct Hero temp[4];
	//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
	fread(&temp, sizeof(struct Hero), 4, f_read);

	for (int i = 0; i < 4;i++)
	{
		printf("姓名:%s  年龄:%d \n", temp[i].name, temp[i].age);
	}
	fclose(f_read);

8.练习: 获取用户键盘输入,写入文件。

假定:用户写入“:wq”终止接收用户输入,将之前的数据保存成一个文件。

FILE *fp = fopen("test07.txt", "w");
if (fp == NULL)
{
	perror("fopen error");
	return -1;
}
char buf[4096] = {0};

while (1)
{
	fgets(buf, 4096, stdin);
	if (strcmp(buf, ":wq\n") == 0)	 // 实际 fgets 读到的是“:wq\n”
	{
		break;
	}
	fputs(buf, fp);
}

fclose(fp);

9.练习: 文件版四则运算:

1. 封装 write_file 函数,将4则运算表达式写入。

	FILE * fp = fopen("w");

	fputs("10/4=\n", fp);

	fputs("10+4=\n", fp);
	....

	fputs("10*4=\n", fp);

2. 封装 read_file 函数, 将4则运算表达式读出,拆分,运算,写回。

	1) 读出:

		FILE * fp = fopen("r");

		while (1) {

			fgets(buf, sizeof(buf), fp);	// buf中存储的 4则运算表达式
		}

	2) 拆分:

		sscanf(buf, "%d%c%c=\n", &a, &ch, &b);	// 得到运算数, 运算符

	3) 根据运算符,得到运算结果

		switch(ch) {

			case '+':
				a+b;
		}

	4) 拼接 结果到  运算式 上

		char result[1024];

		sprintf(reuslt, "%d%c%d=%d\n", a, ch, b, a+b);		// reuslt 中包含带有结果的 运算式。

	5)将 多个带有结果的运算 拼接成一个字符串。

		char sum_ses[4096];	// 存总的字符串  -- "10/2=5\n10*3=30\n4+3=7\n8-6=2\n"

		strcat(sum_ses,reuslt);  // 在while中循环拼接

	6) 重新打开文件, 清空原有 4则运算表达式

		fclose(fp);

		fp = fopen("w");

	7) 将 拼接成一个字符串。写入到空的文件中

		fputs(sum_res);

		printf --- sprintf --- fprintf: 

变参函数:参数形参中 有“...”, 最后一个固参通常是格式描述串(包含格式匹配符), 函数的参数个数、类型、顺序由这个固参决定。

printf("hello");
	
printf("%s", "hello");

printf("ret = %d+%d\n", 10, 5);

printf("%d = %d%c%d\n", 10+5, 10, '+', 5);			--> 屏幕


char buf[1024];   //缓冲区  

sprintf(buf, "%d = %d%c%d\n", 10+5, 10, '+', 5);		--> buf 中

FILE * fp = fopen();

fprintf(fp, "%d = %d%c%d\n", 10+5, 10, '+', 5);			--> fp 对应的文件中

scanf — sscanf — fscanf

scanf("%d", &m);		键盘 --> m


char str[] = "98";

sscanf(str, "%d", &m);		str --> m


FILE * fp = fopen("r");

fscanf(fp, "%d", &m);		fp指向的文件中 --> m

10.fprintf()函数:

写

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

11.fscanf()函数:

读

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

	成功:正确匹配的个数。

	失败: -1

1) 边界溢出。 存储读取的数据空间。在使用之前清空。

2)fscanf函数,每次在调用时都会判断下一次调用是否匹配参数2, 如果不匹配提前结束读文件。(feof(fp) 为真)。

//写文件
FILE * f_write = fopen("./test04.txt", "w");
if (f_write == NULL)
{
	return;
}

fprintf(f_write, "hello world %d年 %d月 %d日", 2018, 7, 5);

//关闭文件
fclose(f_write);

//读文件
FILE * f_read = fopen("./test04.txt", "r");
if (f_read == NULL)
{
	return;
}

char buf[1024] = { 0 };
while (!feof(f_read))
{
	fscanf(f_read, "%s", buf);
	printf("%s\n", buf);
}
fclose(f_read);

按随机位置读写

FILE * f_write = fopen("./test05.txt", "wb");
	if (f_write == NULL)
	{
		return;
	}
struct Hero heros[4] =
{
	{ "亚瑟", 18 },
	{ "赵云", 28 },
	{ "妲己", 19 },
	{ "孙悟空", 99 },
};

for (int i = 0; i < 4; i++)
{
	//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
	fwrite(&heros[i], sizeof(struct Hero), 1, f_write);
}
fclose(f_write);

//读取妲己数据
FILE * f_read = fopen("./test05.txt", "rb");
if (f_read == NULL)
{
	//error 宏 
	
	//printf("文件打开失败\n");
	perror("文件打开失败");
	return;
}

//创建临时结构体
struct Hero temp;

//改变文件光标位置
fseek(f_read, sizeof(struct Hero) *2, SEEK_SET);

fseek(f_read, -(long)sizeof(struct Hero) * 2, SEEK_END);

rewind(f_read); //将文件光标置首

fread(&temp, sizeof(struct Hero), 1, f_read);

printf("姓名: %s 年龄: %d\n", temp.name, temp.age);

fclose(f_read);

12.练习:文件版排序

生成随机数,写入文件。将文件内乱序随机数读出,排好序再写回文件。

fgetc — fputc

fgets — fputs

fprintf – fscanf 默认处理文本文件。

1.fwrite()函数:

既可处理以文本文件。也处理二进制文件。

写出数据到文件中。

stu_t stu[4] = { ...... };

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

	参1:待写出的数据的地址

	参2:待写出数据的大小

	参3:写出的个数				-- 参2 x 参3 = 写出数据的总大小。

	参4:文件

	返回值: 成功:永远是 参3 的值。 --- 通常将参2 传 1. 将参3传实际写出字节数。

		 失败:0 
2.fread()函数:
从文件fp中读出数据。

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

	参1:读取到的数据存储的位置

	参2:一次读取的字节数

	参3:读取的次数				-- 参2 x 参3 = 读出数据的总大小

	参4:文件

	返回值: 成功:参数3.	--- 通常将参2 传 1. 将参3传欲读出的字节数。				

		 0:读失败 -- 到达文件结尾 -- feof(fp)为真。 

13. 练习:大文件拷贝

已知一个任意类型的文件,对该文件复制,产生一个相同的新文件。

1. 打开两个文件, 一个“r”, 另一“w”

2. 从r中 fread , fwrite到 w 文件中。

3. 判断到达文件结尾 终止。  

4. 关闭。

注意: 在windows下,打开二进制文件(mp3、mp4、avi、jpg...)时需要使用“b”。如:“rb”、“wb”

随机位置 读:

1.fseek(),ftell()
文件读写指针。在一个文件内只有一个。

fseek():

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

		参1:文件

		参2:偏移量(矢量: + 向后, - 向前)

		参3:	SEEK_SET:文件开头位置

			SEEK_CUR:当前位置

			SEEK_END:文件结尾位置

	返回值: 成功:0, 失败: -1

ftell():

	获取文件读写指针位置。

	long ftell(FILE *stream);

	返回:从文件当前读写位置到起始位置的偏移量。


​ 借助 ftell(fp) + fseek(fp, 0, SEEK_END); 来获取文件大小。

​ rewind():

​ 回卷文件读写指针。 将读写指针移动到起始位置。

​ void rewind(FILE *stream);

14.Linux和windows文件区别:

1)对于二进制文件操作, Windows 使用“b”, Linux下二进制和文本没区别。

2)windows下,回车 \r, 换行 \n。 \r\n  , Linux下 回车换行\n

3) 对文件指针,先写后读。windows和Linux效果一致。

	       先读后写。Linux无需修改。windows下需要在写操作之前添加 fseek(fp, 0, SEEK_CUR); 来获取文件读写指针,使之生效。

15.获取文件状态:

打开文件,对于系统而言,系统资源消耗较大。

int stat(const char *path, struct stat *buf);

	参1: 访问文件的路径

	参2: 文件属性结构体

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

16. 删除、重命名文件:

int remove(const char *pathname); 删除文件。

int rename(const char *oldpath, const char *newpath);  重名文件

17. 缓冲区刷新:

标准输出-- stdout – 标准输出缓冲区。 写给屏幕的数据,都是先存缓冲区中,由缓冲区一次性刷新到物理设备(屏幕)

标准输入 – stdin – 标准输入缓冲区。 从键盘读取的数据,直接读到 缓冲区中, 由缓冲区给程序提供数据。

//文件的读写也存在缓冲区, fclose 可以用来刷新缓冲区

预读入、缓输出。

行缓冲:printf(); 遇到\n就会将缓冲区中的数据刷新到物理设备上。

全缓冲:文件。 缓冲区存满, 数据刷新到物理设备上。

无缓冲:perror。 缓冲区中只要有数据,就立即刷新到物理设备。

文件关闭时, 缓冲区会被自动刷新。 隐式回收:关闭文件、刷新缓冲区、释放malloc

手动刷新缓冲区: 实时刷新。

​ int fflush(FILE *stream);

​ 成功:0

​ 失败:-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值