c语言文件操作详解!!!(上)

发布于:2022-11-28 ⋅ 阅读:(915) ⋅ 点赞:(0)

1. 为什么使用文件

2. 什么是文件

3. 文件的打开和关闭

4. 文件的顺序读写

 1. 为什么使用文件

我们前面学习结构体时,写了通讯录的程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数 据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯 录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。 我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。 这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据 库等方式。 使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。

2. 什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

程序文件

     包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境 后缀为.exe)。

数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件。

 我们在之前所学的都是输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显 示器上。

所以其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。

文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

没了文件名我们就很难找到这个文件!!!!

例如: c:\code\test.txt

上述是我们的绝对路径

在此我们引入绝对路径和相对路径以便后面内容学习

绝对路径和相对路径

绝对路径

直接在文件夹上面复制的地址是

E:\学习\编程\CSDN图片\c与excel

但是我们知道了绝对地址,但是我们要记住在c语言中要表述单斜杠需要用\\来表示单斜杠,

因为c语言标准规定\+什么,就是个转义字符,结果就不是我们想要的结果了。

正确方式:

E:\\学习\\编程\\CSDN图片\\c与excel

相对路径

一个斜杠 /
两个斜杠 \\ 均可

当前目录

.\\xxx 
./

前一段目录

..\\
../
均表示前一级目录
..\\..\\
../..
均 表示前两级目录

3.文件的打开和关闭

文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。 每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名 字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统 声明的,取名FILE.

我们看看文件类型是怎么声明的,我们的文件类型是包含在stdio.h下的

#include <stdio.h>
int main()
{
    struct _iobuf {
        char* _ptr;
        int   _cnt;
        char* _base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char* _tmpfname;
    };
    typedef struct _iobuf FILE;
}

              不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息, 使用者不必关心细节。

打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。

 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

FILE* pf;//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变 量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联 的文件。

 

 文件的打开和关闭函数

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指 针和文件的关系。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

 

 下面我们来使用下fopen

#include <stdio.h>
int main()
{
    FILE* pFile;
    //打开文件
    pFile = fopen("D:\\code\\text.txt", "w");//因为fopen函数返回文件信息区域的地址
    //文件操作
    if (pFile != NULL)//我们在打开失败的时候会返回空,所以我们在这边判断不为空才能执行
    {                 //因为我们返回空的时候得不到地址,在执行关闭文件时会出问题,
                      //程序会崩溃,因为我们关闭的是空指针的地址区域
        fputs("fopen example", pFile);
        //关闭文件
        fclose(pFile);
        pFile=NULL;
    }
    return 0;
}


//我们也可以
//FILE* pflie=fopen("D:\\code\\text.txt", "w");

所以上述我们看到为什么要去判断是否为空的理由

 

所以我们看看没执行上述代码时

执行前

执行过后


4. 文件的顺序读写

我们来看看这些顺序读写的函数怎么使用。

 在学使用之前我们得知道他的输入输出流

    标准输入文件 stdin(表示键盘)//stdin和stdout这两个流默认是打开的,所以我们在scanf和printf时不需要去打开。

    标准输出文件 stdout(表示显示器)

    标准错误文件 stderr(表示显示器)是由系统打开的,可直接使用。
 

fegtc函数

 fgetc()函数的功能是从文件指针指定的文件中读入一个字符,该字符的ASCII值作为函数的返回值,若返回值为EOF,说明文件结束,EOF是文件结束标志,值为-1。

在文件处理中,通过fgetc()函数,我们从输入流中获取下一个字符,并将文件指针加1

实现一下,看下串代码

1.

stdin流

#include <stdio.h>
int main()
{
	/*FILE* file = fopen("D:\\code\\text.txt", "w");*/
	int ch = 0;
	while ((ch=fgetc(stdin))!=EOF)//这个意思是每次读取键盘上的字符,
		                          //读到没有为止,读到文件尾或者文件读写错误
								  // 会返回EOF
		                          //EOF=-1
	{
		printf("%c", ch);
	}
	return 0;
}

 

 2.

文件流

#include <stdio.h>
int main()
{
	FILE* file = fopen("D:\\code\\text.txt", "w");//返回文件信息区域,所以file保存的是文件信息区域地址
	if (NULL == file)
	{
		perror(fopen);
		return 1;
	}
	int i = 0;
	for(i=0;i<26;i++)
	{
		fputc('a' + i, file);//写入到文件信息区域(内存)然后在写入到D盘下的code里的text.txt文件
	}
	int ch = 0;
	while ((ch=fgetc(file))!=EOF)//读取成功继续执行——继续读取(因为fgetc每次只能读取一个字符),因为每次执行时,文件指针+1
	{                      //所以他会读取下一个字符,如果
						   //读取失败就退出while循环;
		printf("%c", ch);
	}
	fclose(file);
	file = NULL;
	return 0;
}

 仔细想想为什么没有输出

 正确代码:

fputc函数

  fputc()函数的功能是从文件指针指定的文件中写入一个字符,该字符的ASCII值作为函数的返回值,若返回值为EOF,说明文件结束,EOF是文件结束标志,值为-1。

 C 库函数 int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流stream中,并把位置标识符往前移动。

1.

stdout流

#include <stdio.h>
int main()
{
	FILE* pf = fopen("D:\\code\\text.txt","w");
	int c = 65;
	while (fputc(c, stdout) != EOF)
	{
		c++;
		if (c > 90)
		{
			break;
		}
	}
	return 0;
}

2.

文件流 

 那我们用fputc把数据写入到文本中

 

#include <stdio.h>
int main()
{
	FILE* pf = fopen("D:\\code\\text.txt","w");
	int i = 0;
		for(i=0;i<26;i++)
		{
			fputc('a' + i, pf);//写入到文件信息区域(内存)然后在写入到D盘下的code里的text.txt文件
		}
	return 0;
}

 执行后成功写入

 fgets函数

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

str:  char 字符型指针,指向存储读入数据的缓冲区的地址

num:  从流中读入n-1个字符

stream : 指向读取的流。 

          1. 当n<=0 时返回NULL,即空指针。

          2. 当n=1 时,返回空串"".

          3. 如果读入成功,则返回缓冲区的地址。

          4. 如果读入错误或遇到文件结尾(EOF),则返回NULL.

那为什么会造成这种1和2这种现象呢?

原来是因为

fgets()函数的第2个参数指明了读入字符的最大数量。如果该参数的值是n,那么fgets()将读入n-1个字符,因为会在最后放一个\0,或者读到遇到的第一个换行符为止,所以我们就会少读入一个字符.

 

我们来试验一下

 

 

 已知我们的txt文件存了czcxzc

 

#include <stdio.h>
int main()
{
	FILE* pf = fopen("D:\\code\\text.txt","r");
	if (NULL == pf)
	{
		perror(fopen);
		return 1;
	}
	char arr[] = "*******";
	fgets(arr,7, pf);
	printf("%s", arr);
	return 0;
}

在我们执行这个代码后

 所以我们知道arr里面存了6个字符加一个\0

 不过这里也要提醒一下小伙伴们,fgets函数会读取\n,不会丢弃!!!!

1.

stdin流

#include <stdio.h>
int main()
{
	char arr[10] = { 0 };
	fgets(arr, 10, stdin);
	puts(arr);
	return 0;
}

 2.

文件流

#include <stdio.h>
int main()
{
	FILE* pf = fopen("D:\\code\\text.txt","r");
	if (NULL == pf)
	{
		perror(fopen);
		return 1;
	}
	char arr[] = "*******";
	fgets(arr,7, pf);
	printf("%s", arr);
	return 0;
}

 

 fputs函数

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

 C 库函数 int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但不包括空字符

 1.

stdout流

 2.

文件流

#include <stdio.h>
int main()
{
	FILE* file = fopen("D:\\code\\text.txt", "w+");
	FILE* cunfile = file;
	if (NULL == file)
	{
		perror(fopen);
		return 0;
	}
	char arr[] = "abcde0";
	fputs(arr,file);
	char arr1[10] = { 0 };
	fgets(arr1, 7, cunfile);
	printf("%s", arr1);
	fclose(file);
	file = NULL;
	return 0;
}

fscanf()函数

int fscanf(FILE*stream, constchar*format, [argument...]);

其功能为根据数据格式(format)从输入流(stream)中写入数据(argument);

1. format str:如%d, %f, %c, %s等,分别表示读入一个整数,浮点数,字符,字符串。还可以加上控制,如%ld,表示读入一个长整型数,%20s表示最多读入20个字符。 

2.返回值:在没有出错的情况下,fscanf 返回正确匹配和赋值的域的个数;如果出错,则返回EOF。 

其实fscanf()函数与scanf()函数类似

 1.

stdin流

 2.

文件流

已知文本存了abcde0

 
 fprintf()函数

 fprintf()的返回值是输出的字符数,发生错误时返回一个负值.

可以看到,它与printf()函数相比多出来了第一个参数FILE *stream,其意义是将打印的内容输出到文件流指针stream指向的流.

1.

stdout流

 

#include <stdio.h>
int main()
{
	char arr[10] = { 0 };
	FILE* file = fopen("D:\\code\\text.txt", "r+");
	fscanf(file, "%s", arr);
	fprintf(stdout,"%s",arr);
	return 0;
}

2.

文件流 

#include <stdio.h>
int main()
{
	char arr[10] = "***";
	FILE* file = fopen("D:\\code\\text.txt", "r+");
	fprintf(file,"%s",arr);
	return 0;
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到