文件类的函数及注意事项

一、什么是文件
文件
磁盘文件:指一组相关数据的有序集合,通常存储于外部介质(如磁盘)上,使用时才调入内存。
设备文件:在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读写。比如stdin、stdout
文本文件:存的是字符的ASCII码值存在磁盘中。
打开文件:
格式:FILE*p=fopen(“pathname”,打开的方式);
./打开当前路径下
返回的文件流指针表示了“a.txt”这个文件
fopen(“a.txt”);//调用fopen时,返回的是这个结构体的地址
如果成功返回FILE结构体地址,失败返回NULL

文件第二个参数打开方式:
r或rb 以只读方式打开一个文件,不存在,不创建
w或wb 以写方式打开文件(文件存在清空文件,文件不存在则创建一个文件)
a或ab 以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件
r+或rb+ 以可读、可写方式打开文件(不创建新文件)
w+或wb+ 以可读可写的方式打开文件(若文件存在则清空文件,不存在则创建一个文件)
a+或ab+ 以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件
关闭文件
fclose§;
二、字符文件函数(这里也不知道讲的对不对,总之就是对文件中的单个字符进行操作的函数)
函数:fgetc()与fputc()
2.1 fputc()
功能:写入一个字符到文件中
include <stdio.h>
int fputc(int ch, FILE* stream);
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
ch:需要写入文件的字符
stream:文件指针
返回值:
成功:成功写入文件的字符
失败:返回 - 1

FILE* fp = fopen("fputc.txt", "w");
	char buf[] = "hello world";
	int len = sizeof(buf);
	int i = 0;
	while (len)
	{
		fputc(buf[i++], fp);
		len--;
	}
	fclose(fp);

2.2fgetc()函数
#include <stdio.h>
int fgetc(FILE* stream);
功能:从stream指定的文件中读取一个字符
参数:
stream:文件指针
返回值:
成功:返回读取到的字符
失败: - 1

FILE* fp = fopen("fputc.txt", "r");
	char buf[13];
	int i = 0;
	while ((buf[i++] = fgetc(fp)) != EOF);//此处并不完善,因为无法断定文件到底是读取到了-1字符,或是读取出错,或者是到达文件尾所造成的结束。所以后续的feof()会有介绍
	printf("%s\n", buf);
	fclose(fp);

三、字符串类文件操作函数
fputs与fgets()
3.1fpus函数
int fputs(const char* str, FILE* stream);
功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 ‘\0’ 不写入文件。
参数:
str:字符串
stream:文件指针
返回值:
成功:0
失败: - 1

char buf[15] = "hello world\n";
	char buf1[12] = "hello";
	FILE* fp = fopen("fputs.txt", "w");
	if (fp == NULL)
	{
		perror(" ");
	}
	fputs(buf, fp);
	fputs(buf1, fp);
	fclose(fp);

3.2fgets()函数
fgets 从文件读取字符串
注意 : fgets读取遇到\n结束
#include <stdio.h>
char* fgets(char* str, int size, FILE * stream);
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 ‘\0’ 作为字符串结束。
参数:
str:字符串
size:指定最大读取字符串的长度(size - 1)(因为最后一位留给\0)
stream:文件指针
返回值:
成功:成功读取的字符串
读到文件尾或出错: NULL

FILE* fp = fopen("fputs.txt", "r");
	if (fp==NULL)
	{
		perror(" ");
	}
	char buf[128];
	fgets(buf, 128, fp);//此时在fputs文件中有hello world\n hello 两个字符串,但由于读取到了\n字符,所以停止读取
	printf("buf=%s\n", buf);
	fclose(fp);

四、拆包函数与组包函数
fscanf()与fprintf()
4.1、fprintf()使用(组包函数)
int fprintf(FILE* stream, const char* format, …);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 ‘\0’ 为止。
参数:
stream:已经打开的文件
format:字符串格式,用法和printf()一样
返回值:
成功:实际写入文件的字符个数
失败: - 1

//与printf()函数区别:printf()是将结果输入到终端,
//但fpritnf()是将结果输入进文件中
	//stdin键盘输入 \stdout终端 \  stderr保存的是错误信息
	fprintf(stdout, "%s", "hello world");//相当于printf,
	//因为stdout对应的就是黑窗口
	int year, month, day;
	fscanf(stdin, "%d %d %d", &year, &month, &day);//stdin此时相当于
	//scanf("%d %d %d",&year,&month,&day);
	printf("%d年%d月%d日\n", year, month, day);

4.2fscanf()函数(拆包函数)
#include <stdio.h>
int fscanf(FILE * stream, const char* format, …);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
stream:已经打开的文件
format:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1

FILE* fp = fopen("fprintf.txt", "rb");
	if (fp == NULL)
	{
		perror("");
		return;
	}
	int year, month;//此时文件中存的是2020年7月
	fscanf(fp, "%d年%d月", &year, &month);//使用fscanf()注意:1.要保证需要读取数据格式的正确,
	//2.在文件中是什么样子,你读取相应数据时除了数据外也必须呈现相应的格式,要不会造成后续数据的错误读取。

	printf("%d\t%d\n", year, month);

五、fwrite()与fread()函数
5.1fwrite函数

#include <stdio.h>
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE * stream);
功能:以数据块的方式给文件写入内容
参数:
ptr:准备写入文件数据的地址
size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
nmemb:写入文件的块数,写入文件数据总大小为:size* nmemb
stream:已经打开的文件指针
注:一般默认情况下有两种写法,
fwrite(&str,1,sizeof(str),fp);//str为在栈上开辟的空间,
fwrite(&str,sizeof(arr),1,fp);
总结:就是必须要满足size*nmemb的值等于你所要写入的字节大小。搭配是随意的。

struct student
{
	char name[15];
	int age;
	double score;
};
void test01()
{
	struct student* temp = MAlloc1(struct student,5 );
	if (temp == NULL)
	{
		return;
	}
	FILE* fp = fopen("fwrite.txt", "wb");
	for (size_t i = 0; i < 5; i++)
	{
		printf("请输入姓名\n");
		scanf("%s", &temp[i].name);
		printf("请输入年龄\n");
		scanf("%d", &temp[i].age);
		printf("请输入成绩\n");
		scanf("%lf", &temp[i].score);
		fwrite(&temp[i], 1, sizeof(struct student), fp);//可以一个一个写进去
		printf("第%d 个人信息录入完成\n", i + 1);
	}
	//也可以全部进行写入,看自己喜好,一般会尽可能使用下面这种写法。
	//fwrite(&(*temp),1,sizeof(struct student)*5,fp);
	free(temp);
	temp = NULL;
	fclose(fp);	
}

5.2 fread()函数。
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式从文件中读取内容
参数:
ptr:存放读取出来数据的内存空间(一般值结构体数组名)
size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
stream:已经打开的文件指针
返回值:
成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
失败:0

FILE* fp = fopen("fwrite.txt", "rb");
	if (fp == NULL)
	{
		return;
	}
	int k = 0;
	struct student temp[5];
	int cont;
	cont = fread(&temp, 1, sizeof(struct student)*5, fp);
	for (int i = 0; i < 5; i++)
	{
		//cont = fread( &temp[i] ,1,sizeof(struct student),fp );
		printf("cont =%d\n",cont);
		printf("%d %s %lf\n", temp[i].age, temp[i].name,temp[i].score);

	}

六、fseek()函数

#include <stdio.h>
int fseek(FILE* stream, long offset, int whence);
功能:移动文件流(文件光标)的读写位置。
参数:
stream:已经打开的文件指针
offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,
则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
whence:其取值如下:
SEEK_SET:从文件开头移动offset个字节
SEEK_CUR:从当前位置移动offset个字节
SEEK_END:从文件末尾移动offset个字节
返回值:
成功:0
失败: - 1

 FILE* fp = NULL;
    fp = fopen("fseek.txt", "wb");
    if (!fp)
    {
        perror("");
        return -1;
    }
    fputs("helloworld", fp);
    fseek(fp, 0, SEEK_SET);//移动光标到头
    fputs("seek", fp);
    fseek(fp, -20, SEEK_END);//?超过怎么办?
    fputs("abc", fp);
    fclose(fp);
    system("pause");
    return 0;

七、缓冲区问题
缓冲区本质:内存中的一块临时空间
为什么要引入缓冲区?

  1. 这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
  2. 它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。
    刷新缓冲区的三种情况
    1.使用fflush函数强制刷新
    头文件 #include<stdio.h>
    原型int fflush(FILE *fp);
    返回值:成功为0,失败为EOF
    2.程序结束
    3.缓冲区满的情况
    八、自己所遇到的一些问题
    1.fseek()函数移动越界怎么处理?
    2.remove函数删除失败的原因?
    3.静态全局变量的作用域到底怎么有效的扩展?

好久没发过博客了,文件作为c语言中必不可少的组成,学好它们是做到熟练应用的前提。其实文件还有些许函数,比如ftell、remove、rename、rewind函数、还有stat获取文件状态的这一类东西,在这里并未呈现,因为感觉写的太多会影响观感,纯文字确实看着挺累的。当然有需要的评论我后续会分享出来,对于上面自身的一些困惑,也希望各位知道的大佬们可以不吝赐教。不胜感谢、

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值