C语言文件操作

文件操作

文件操作中相关的函数的头文件都是stdlib.h

文件的打开和关闭

打开文件

FILE* fopen(const char* filename, const char* mode);
返回值:FILE*是返回一个文件指针
filname是文件名
mode是打开文件的方式
打开成功返回文件信息区的地址,失败返回NULL

下面是文件的打开方式
在这里插入图片描述

代码解释如何打开文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
	if(pf == NULL)//文件打开失败
	{
		perror("fopen");//返回打开失败的原因
		return 1;//异常返回
	}
}

关闭文件

int fclose(FILE* stream);
stream是流,也就是文件指针

代码解释关闭文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
	if(pf == NULL)//文件打开失败
	{
		perror("fopen");//返回打开失败的原因
		return 1;//异常返回
	}
	else
	{
		printf("打开成功\n");
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

文件打开路径

绝对路径

#include <stdio.h>
#include <stdlib.h>

int main()
{
					//绝对路径
	FILE* pf = fopen("C:\\Users\\48784\\Desktop\\test.txt", "r");//以读的形式打开文件
	if(pf == NULL)//文件打开失败
	{
		perror("fopen");//返回打开失败的原因
		return 1;//异常返回
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

相对路径

#include <stdio.h>
#include <stdlib.h>

int main()
{
	//相对路径
	// . --> 当前路径
	// .. --> 上一级路径
	//   /这样写不用转义  \这样写需要转义
	//FILE* pf = fopen("./../test.txt", "w");//在当前路径的上一个路径找test.txt
	//FILE* pf = fopen(".\\..\\test.txt", "w");
	
	FILE* pf = fopen("./../x64/test.txt", "w");//在当前路径的上一个路径的x64文件中找test.txt
	
	if(pf == NULL)//文件打开失败
	{
		perror("fopen");//返回打开失败的原因
		return 1;//异常返回
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

文件的顺序读写

顺序读写函数介绍

在这里插入图片描述
上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(入文件输入流)

fputc

字符输出函数 fputs
int fputc(int character, FILE* stream);
character是要写的字符
stream是流,也就是文件指针
fputc函数的作用:将字符写到文件中

写字符到文件中

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");//以写的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写字符到文件
	fputc('a', pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

	//写字符到文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
	fputc('e', pf);

在这里插入图片描述

	//写字符到文件
	for(int i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}
}

在这里插入图片描述

fgetc

字符输入函数 fgetc
int fgetc(FILE* stream,);
stream是文件指针
fgetc函数的作用:从文件中读取字符。
读取成功返回字符的ASCII码值
当读取文件结束时有两种情况
1.遇到错误而结束,并设置一个遇到错误而结束的标记,返回EOF(-1)
2.遇到文件末尾而结束,并设置一个遇到文件末尾而结束的标记,返回EOF(-1)

从文件中读取字符

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//从文件中读取字符
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

//从文件中读取字符
int ch = 0;
while((ch = fgetc(pf)) != EOF)
{
	printf("%c ", ch);
}

在这里插入图片描述

fputs

文本行输出函数 fputs
int fputs(const char* str, FILE* stream);
str是要写的字符串
stream是文件指针
fputs的作用:向文件中写一个字符串

向文件中写一个字符串

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");//以写的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中写一个字符串
	fputs("hello world", pf);
	fputs("hello bit", pf);//该函数不会自动换行
	
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

	//向文件中写一个字符串
	fputs("hello world\n", pf);
	fputs("hello bit\n", pf);//该函数不会自动换行

在这里插入图片描述

fgets

文本行输入函数 fgets
char* fgets(char* str, int num, FILE* stream);
str是读取到的字符串
num是读取的字符的个数
stream是要被读取的文件

从文件中读一个字符串

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//从文件中读一个字符串
	char arr[20];
	fgets(arr, 8, pf);//假设test.txt中的字符串为abcdefghijk,共11个字符,末尾还有一个\0
	//此时该函数会读取num-1个字符也就是7个字符放在arr中,末尾加上\0
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

//从文件中读一个字符串
fgets(arr, 20, pf);//假设test.txt中的字符串为abcdefghijk,共11个字符,末尾还有一个\0,并且换行了。
//此时该函数会读取11个字符,再加上\n\0

在这里插入图片描述

在这里插入图片描述

fprintf

格式化输出函数 fprintf
int fprintf(FILE* stream, const char * format, …);
该函数与printf不同之处就是加了一个stream参数
fprintf函数的作用:向文件中写数据

向文件中写数据

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");//以写的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中写数据
	char arr[20] = "hello";
	int num = 100;
	double pai = 3.14;
	fprintf(pf, "%s %d %.2lf", arr, num, pai);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

struct S
{
	char arr[20];
	int num;
	double pai;	
};

int main()
{
	FILE* pf = fopen("test.txt", "w");//以写的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中写数据
	struct S s = {"world", 200, 3.14}
	fprintf(pf, "%s %d %.2lf", s.arr, s.num, s.pai);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

fscanf

格式化输入函数 fscanf
int fsacnf(FILE* stream, const char * format, …)
该函数与scanf不同之处就是加了一个stream参数
fscanf函数的作用:从文件中读取数据

#include <stdio.h>
#include <stdlib.h>

struct S
{
	char arr[20];
	int num;
	double pai;	
};

int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//从文件中读数据
	struct S s = { 0 };
	fscanf(pf, "%s %d %lf", s.arr, &(s.num), &(s.pai));
	printf("%s %d %lf\n", s.arr, s.num, s.pai);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

fscanf(stdin, "%s %d %lf", s.arr, &(s.num), &(s.pai));
//等价于
scanf("%s %d %lf", s.arr, &(s.num), &(s.pai));

stdin是标准输入流,在大多数的环境中从键盘输入
那么

fprintf(stdout, "%s %d %lf", s.arr, s.num, s.pai);
//等价于
printf("%s %d %lf\n", s.arr, s.num, s.pai);

stdout是标准输出流,大多数的环境中输出至显示器界面

fwrite

二进制输出 fwrite 只针对文件输出流
size_t fwrite(const void** ptr, size_t size, size_t count, FILE* stream);
fwrite函数的作用:写数据块到流(文件)中
ptr是要被写的数据块
size是要被写的数据块的元素的大小,也可以说是每次要写的字节大小
count是要写的元素的个数,也可以说是要写的次数
pf是要写的文件

二进制的形式写文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("bin.txt", "wb");//以二进制写的形式打开文件
	//wb就是write binary 二进制写
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//二进制的形式写文件
	int arr[] = {1, 2, 3, 4, 5};
	fwrite(arr, sizeof(arr[0]), 5, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

	//二进制的形式写文件
	int arr[] = {1, 2, 3, 4, 5};
	fwrite(arr, 20, 1, pf);//一次写20个字节写1次

在这里插入图片描述

fread

二进制输入 fread 只针对文件输入流
size_t fread(const void* ptr, size_t size, size_t count, FILE* stream);
fread函数的作用:从流(文件)中读取数据块
ptr中放的是从(文件)中读取到的数据块
size是要读取的数据的元素的大小,也可以说是每次要读的字节的大小
count是要读的元素的个数,也可以说是要读的次数
stream是要被读的文件

二进制的形式读文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("bin.txt", "rb");//以二进制读的形式打开文件
	//rb就是read binary 二进制读
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//二进制的形式读文件
	int arr[10] = { 0 };
	fread(arr, sizeof(arr[0]), 5, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

在这里插入图片描述

	//二进制的形式读文件
	int arr[10] = { 0 };
	fread(arr, 20, 1, pf);//要读20个字节,读一次

对比一组函数

scanf / fscanf / sscanf
printf / fprintf / sprintf

前面的两组我们都学过,先说说最后一组再对比

sprintf

int sprintf(char* str, const char * format, …)
sprintf函数的作用:将格式化的数据转换成字符串放在str中

#include <stdio.h>
#include <stdlib.h>

struct S
{
	char arr[20];
	int num;
	double pai;
};

int main()
{
	struct S s = { "world", 201, 3.14 };
	char arr[30] = { 0 };
	sprintf(arr, "%s %d %lf", s.arr, s.num, s.pai);
	printf("%s\n", arr);
	return 0;
}

在这里插入图片描述

sscanf

int sscanf(const char* s, const char* format, …);
将字符串转换成格式化的数据

#include <stdio.h>
#include <stdlib.h>

struct S
{
	char arr[20];
	int num;
	double pai;
};

int main()
{
	struct S s = { "world", 201, 3.14 };
	char arr[30] = { 0 };
	sprintf(arr, "%s %d %lf", s.arr, s.num, s.pai);
	printf("字符串:%s\n", arr);
	struct S t = { 0 };
	sscanf(arr, "%s %d %lf", s.arr, &(s.num), &(s.pai));
	printf("结构体:%s %d %lf\n", t.arr, t.num, t.pai);
	return 0;
}

在这里插入图片描述

对比

scanf/printf 针对标准输入(stdin-键盘)输出(stdout-屏幕)流的格式化的输入/输出函数
fscanf/fprintf 针对所有输入流/所有输出流的格式化的输入/输出函数
sscanf 将字符串转换成格式化的数据
sprintf 将格式化的数据转换成字符串

文件的随机读写

fseek

int fseek(FILE* stream, long int offset, int origin);
stream是流(文件)
offset是偏移量
origin是位置
fseek函数的作用:根据文件指针的位置和偏移量来定位文件指针(文件内容中的光标)
origin有三个取值
SEEK_SET 文件起始位置
SEEK_CUR 文件指针(文件内容中的光标)的当前位置
SEEK_END 文件末尾位置

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//假设test.txt中是abcdef
	int ch = fgetc(pf);
	fputc(ch, stdout);//'a'
	//定位文件指针指向'd'
	fseek(pf, 3, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	//fseek(pf, -3, SEEK_END);//这三种写法都行
	ch = fgetc(pf);
	fputc(ch, stdout);//'d'

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

在这里插入图片描述

ftell

long int ftell(FILE* stream);
ftell函数的作用:返回文件指针相对于起始位置的偏移量

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//假设test.txt中是abcdef
	int ch = fgetc(pf);
	fputc(ch, stdout);//'a'
	//定位文件指针指向'd'
	fseek(pf, 3, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	//fseek(pf, -3, SEEK_END);//这三种写法都行
	ch = fgetc(pf);
	fputc(ch, stdout);//'d'
	//此时文件光标指向'e'
	//计算'e'相对于起始位置的偏移量
	long int r = ftell(pf);
	printf("%ld\n", r);//4

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

在这里插入图片描述

rewind

void rewind(FILE* stream);
rewind函数的作用:让文件指针回到起始位置

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	fputc(ch, stdout);//'a'
	//定位文件指针指向'd'
	//fseek(pf, 3, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	fseek(pf, -3, SEEK_END);
	ch = fgetc(pf);
	fputc(ch, stdout);//'d'
	//文件指针(光标)指向'e'
	//计算'e'相对于起始位置的偏移量
	long int r = ftell(pf);
	printf("%ld\n", r);//4
	//让文件指针回到起始位置
	rewind(pf);
	ch = fgetc(pf);
	fputc(ch, stdout);//'a'

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述

文件读取结束的判定

当读取文件结束时,有两种情况
1.遇到文件末尾而结束
2.遇到错误而结束

回忆fgetc
当fgetc读取结束时,有两种情况
1.遇到文件末尾而结束,并设置一个遇到文件末尾而结束的标记,返回EOF
2.遇到错误而结束,并设置一个遇到错误而结束的标记,返回EOF

函数feof的作用:当文件读取结束的时候,判断读取结束的原因是否为:遇到文件末尾而结束
函数ferror的作用:当文件读取结束的时候,判断读取结束的原因是否为:遇到错误而结束

如何判断文件读取结束?

1.对于文本文件读取是否结束,判断返回值是否为EOF,或者NULL
例如:
fgetc判断是否返回EOF
fgets判断是否返回NULL
2.对于二进制文件读取是否结束,判断返回值是否小于实际要读的个数
例如:
fread判断返回值是否小于实际要读的个数

文本文件的例子

#include <stdio.h>
#include <stdlib.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		fputc(ch, stdout);
	}

	//判断文件读取结束的原因
	if (feof(pf))
		printf("遇到文件末尾\n");
	else if (ferror(pf))
		printf("遇到错误\n");

	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

二进制文件的例子

#include <stdio.h>
#include <stdlib.h>

enum { SIZE = 5 };

int main(void)
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	FILE* fp = fopen("bin.txt", "wb"); //必须⽤⼆进制模式
	fwrite(a, sizeof * a, SIZE, fp); // 写double的数组
	fclose(fp);
	double b[SIZE];
	fp = fopen("bin.txt", "rb");
	size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读double的数组
	if (ret_code == SIZE) 
	{
		printf("读取文件成功\n");
		for (int n = 0; n < SIZE; ++n)
			printf("%f ", b[n]);
		putchar('\n');
	}
	else 
	{ 
		if (feof(fp))
			printf("遇到文件末尾而结束\n");
		else if (ferror(fp))
		{
			perror("遇到错误未结束\n");
		}
	}
	fclose(fp);
}

在这里插入图片描述
请添加图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值