c语言:文件操作

目录

前言

一、什么是流

二、文件的打开和关闭

1.文件的打开

2.文件的关闭

三、文件的标准化输入输出

1.概念

2.例子

四、fgets() 和 fputs() 

1.fputs() 字符串输出

2.fgets() 字符串输入

五、二进制读取与写入

        1.fwrite() 

        2.fread()

六、文件指针操作函数

        1.rewind()

        2.fseek()

实例:

        3.ftell()

七、文件末尾的判断

1. 观察各种读取函数的返回值

2. 使用 feof() 函数

结语


前言

        在平时的的程序运行的时候,一旦程序结束,这个程序相关的内容就消失了,我们也就无法长久的保留相关的信息了,而只要我们掌握了文件的相关操作,我们就可以长久的保留信息了。下面就来讲一讲c语言中关于文件的相关操作。

一、什么是流

        要学习文件的操作,首先得了解什么是流。

        流可以理解为流淌着字符,数字等内容的河流。我们平时的键盘的输入和屏幕的输入都是对流的输入和读取的操作。 像我们平时在黑窗口输入的就是标准输入流,输出的就是标准输出流。这两个还有标准错误流都是在程序一开始时就打开的。

二、文件的打开和关闭

1.文件的打开

        要使用文件,我们就得打开文件,把我们的要存储的信息放到文件里。这里就要用到 fopen 函数了。

下面是对函数的的讲解:

函数原型:
FILE * fopen ( const char * filename, const char * mode );

1.返回类型:

        返回的是 FILE 类型的指针。

        FILE 类型其实就是一个结构体,是包含在头文件 stdio.h 里面,在程序中是已经声明好的,我们包含了头文件后就不用自己在声明了。

2.第一参数:

        其中的 filename 的就是要打开的文件的名字,也即是文件的地址,是一个字符串。

        文件名包括:文件路径 + 文件名主干 + 文件后缀

地址有 绝对路径 相对路径:

绝对路径 其实也就是基于当前这台电脑的,也就是地址的全称,什么情况下都可以用。

相对路径 就是基于当前文件夹下的地址,也就是有些被省略了。

两个类型的路径举例:
绝对:"C:\\Users\\zl\\Desktop\\data.txt"     \ 要由另一个 \ 来转义,表示的其就只是一个 \
相对:"data.txt"  或  "..\\Debug\\data.txt"
例子中一个 . 表示当前文件夹下(文件后缀前面的点不算),两个 . 表示当前文件夹的上一个文件夹下,而上一级文件夹的上一级就是 ..\\..

3.第二参数

        其中的 mode 就是要操作文件的模式,也是一个字符串。

下面是部分的操作模式:

小结:

1.操作模式可以分为三类:读 写 追加   (追加其实也是写的一种)

2.在三类的基础上还有别的,如 加上 b ,就是操作二进制文件,加上 + ,就是既要读也要写,也可以有 b 也有 + ,就是对二进制文件进行读写操作的意思(可以参考上表)

3.这三类中,如果操作的文件不存在,会有不同的反应,总的来说,就是写文件不存在,就创建新文件,读文件不存在就报错,而如果有 + 号的话,则要依据三个类型来判断,w 和 a 就是创建新文件,r 就是报错,如 "r+", 就是报错。

4.还有一点就是,用 "w" 模式时,如果文件存在,文件内部的信息会清空

        在开启文件后,文件指针会指向一个位置,然后我们的读取和写入都会在当前位置进行,"w" 和 "r" 模式 fopen() 返回的指针都是指向文件的开头位置的。"a" 模式返回的指针就是已有数据的下一个位置。  

2.文件的关闭

        在程序中使用完一个文件,我们要关闭当前的文件,避免后续不小心对文件进行修改。这就要用到 fclose() 函数了

函数原型:
int fclose ( FILE * stream );

        fclose() 函数的使用就很简单了,把要关闭的文件的指针放在括号中,关闭成功就会返回 0,否则就返回 EOF

三、文件的标准化输入输出

1.概念

        标准化输入输出的函数分别是 fscanf() 和 fprintf() 。这两个函数的使用很简单,相较我们平时使用的 scanf() 和 printf() ,就是最前面多了一个参数,这个参数填的就是流,如果我们分别填入 stdin(标准输入流) 和 stdout(标准输出流),那么这两个函数就和我们平时使用的 scanf 和 printf 一样了,都是在控制台里得到和输出数据。

2.例子

下面我们来实践一下:

        这是一段代码:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("data.text", "w+"); //文件名处在未写明时默认是在当前文件夹下
	if (pf == NULL)
	{
		return 1;
	}
	fprintf(pf, "%d %c", 1, 'a');
	
	fclose(pf); //文件关闭一般不会有问题
	
	return 0;
}

        在运行了这段代码后,该文件夹下的 data.text 文件

        没有问题,数据已经被我们输入到文件里面了。

        再看看这个代码:

         为什么读取的信息有问题呢?相信大家注意到了被我注释掉的 rewind(pf) 了,来看看没有注释掉的情况:

        结果正确,这因为在写入和读取的时候,文件指针是在移动的(可以想想我们平时输入和删除时的小横线),而 rewind() 函数可以把文件指针回到文件的开头。这样读取到的数据就没有问题了。

四、fgets() 和 fputs() 

        利用 fgets() 和 fputs() 就可以实现对字符串的输入输出了。

1.fputs() 字符串输出

        fputs() 的用法和平时使用的 puts() 几乎是一样的,不同的点在于,多了一个参数,也就是流。利用这个函数就可以把字符串输出到想要的流里去。

函数原型:
int fputs ( const char * str, FILE * stream );
2.fgets() 字符串输入

        fgets() 与 gets() 还是有区别的 fgets() 可以限定读取字符的个数,还很有可能把最后的 '\n' 也一起读进来,还有就是多了一个参数,也就是流。别的和 gets() 没什么区别。

 函数原型:

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

        从中读取字符,并将它们作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符或到达换行符或文件末尾,以先发生者为准。(这里的 num-1 可以理解为要读取num个字符,最后一个位置放 '\0',所以前面只有 num-1 个位置能用来放要读取的信息)

        换行符使 fgets 停止读取,但它被函数视为有效字符,并包含在复制到 str 的字符串中。

(gets() 函数是读到 '\n'之前, '\n' 是不会被读入的)

五、二进制读取与写入

        1.fwrite() 

                fwrite() 的作用就是把一个数据的二进制信息写到文件里面去。

        2.fread()

                fread() 的作用就是把文件的二进制信息翻译之后读出来。

        这里就直接上代码演示,方便理解:

struct S
{
	int a;
	float s;
	char str[10];
};
int main()
{
	struct S s = { 99, 3.14f, "hehe" };
	FILE* pf = fopen("data.txt", "wb");//"wb"二进制模式写文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fwrite(&s, sizeof(struct S), 1, pf);//第一参数是要写入的信息的所在地址, 第二参数是要写信息的大小, 第三参数是读取信息块的个数, 第四参数是要写到的位置
	//即把 &s 处的大小为 sizeof(struct S) 的 1 个数据,写到 pf 处
	fclose(pf);
	pf = NULL;
	
	
	struct S x = { 0 };
	pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fread(&x, sizeof(struct S), 1, pf);//返回值是实际读取到的数据块的个数.如果到文件结尾就读取到0个数据块
	//即把 pf 处的大小为 sizeof(struct S) 的 1 个数据,读取到 &x 处
	printf("%d %f %s\n", x.a, x.s, x.str);//打印到黑窗口看看
	fclose(pf);
	pf = NULL;


	return 0;
}

        fread() 的返回值时成功读取到的模块的个数。

六、文件指针操作函数

        1.rewind()

                rewind() 函数在前面有提到(三、2. 例子),这里就不再过多赘述。

        2.fseek()

                fseek() 是可以帮助我们把指针放到我们想要的位置上的一个函数、

原型:

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

这些参数中,第一个放的是要调整的文件指针,第二个是要移动的距离(正数后移,负数前移),第三个就是要从哪里开始移动(这个是规定好的)。

这是第三参数可以填的三个值:

实例:

下面是使用fseek()的一段代码:

#include<stdio.h>
int main()
{
	//写入一些数据
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdefghi", pf);
	fclose(pf);
	pf = NULL;
	//读数据
	pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//fseek的作用就在于调整文件指针的位置(这里就用SEEK_SET为例)
	fseek(pf, 5, SEEK_SET);
	//指针位于开头,偏移量为5,指针指向的就是f(如果在文件头还往前移,就会指向第一个,如果往后移的量超过了已经有了的字符,则任然往后但输出就会是空白方框了)
	int ch = fgetc(pf);//在读取了字符后,ch拿到f,指针就会后移,指向g
	printf("%c\n", ch);//结果为f
	ch = fgetc(pf);//在读取了字符后,ch拿到g,指针后移,指向h
	printf("%c\n", ch);//结果为g
	
	fclose(pf);
	pf = NULL;

	return 0;
}
        3.ftell()

                ftell()就很简单了,只需要在其中放入要查的那个文件指针,它可以告诉我们文件指针当前的位置与文件起始位置的偏移量。

七、文件末尾的判断

        要判断文件指针是否到了文件的末尾有多种方法。

1. 观察各种读取函数的返回值

        大多读取函数在读取时遇到结尾有着不同返回值,观察返回值可以判断读取是否到了文件的末尾。

        例如:

        fgets() 在读取到文件末尾的时候会返回NULL。

        fread() 在读取的时候,如果返回值小于我们给的个数,就是读取到文件末尾了。

        还有很多,可以去官网查查,这里就不多讲了。

2. 使用 feof() 函数

        这个函数可以帮助我们知道当前的文件指针是否到达文件末尾。如果放入的文件指针到达了文件末尾,就会返回非零值,否则返回零。

结语

        以上就是关于文件操作的一些内容,希望对大家有所帮助,最后也别忘了点赞收藏加关注😁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值