Bootstrap

【C语言基础】文件管理


在这里插入图片描述

由于所用函数较多,提供一个比较好用的网址可查询函数相关知识:
函数查询入口(点击即可进入)

一、文件的相关概念

1、C程序主要有两种文件:程序文件和数据文件
2、输入输出流:输入输出数据传送的过程,C中把此称为流
3、文件名:文件路径+文件名主干+文件后缀

D:\cc\temp\     filel   .   dat
  文件路径     文件名主干  文件后缀

4、文件类型:ASCII文件和二进制文件

5、文件缓冲区:指系统自动地在内存区为每一个正在使用的文件开辟一个文件缓冲区

相当于是磁盘和程序数据区的一个中介

6、文件类型指针——FILE(为结构体,有系统提供)

每一个FILE类型变量对应一个文件信息区,其中包含该文件的有关信息

定义文件型指针变量: FILE* fp;

fp 是一个指向FILE类型变量的指针变量,即:通过fp能够找到与它相关的文件

二、文件的打开与关闭——fopen与fclose函数

1、fopen函数打开文件

一般形式:
FILE* fp;    //定义文件型指针变量
fp = fopen(文件名,使用文件方式);
    //使指针变量指向打开的文件的信息区
例如:
fp = fopen("test.txt","r");

//绝对路径的写法:fopen("D:\\office\\VS2013\\file\\test.txt","r");
//相对路径的写法:fopen("test.txt","r");
//或者:fopen("..\\test.txt");//此表示上一级路径
//上上级路径:..\\..\\

常用打开文件的方法:
if ((fp = fopen("test.txt","r")) == NULL){
        //打开失败,fopen 函数会返回一个空指针NULL
    printf("文件打开失败!\n");

    //可用printf("%s\n",strerror(errno));输出出错原因
    //需引头文件 <string.h>  与  <errno.h>

    exit(0);
    //exit为终止的库函数,需引头文件  <stdlib.h>
}
对文件访问的方式
文件访问方式含义文件不存在时
" r "(只读)为输入打开一个已存在的文本文件出错
" w "(只写)为输出打开一个文本文件建立新文件
" a "(追加)向文本文件尾添加数据出错
" rb "(只读)为输入打开一个二进制文件出错
" wb "(只写)为输出打开一个二进制文件建立新文件
" ab "(追加)向二进制文件尾加数据出错
" r+ "(读写)为读写打开一个文本文件出错
" w+ "(读写)为读写建立一个新的文本文件建立新文件
" a+ "(读写)为读写打开一个文本文件出错
" rb+ "(读写)为读写打开一个二进制文件出错
" wb+ "(读写)为读写建立一个新的二进制文件建立新文件
" ab+ "(读写)为读写打开一个二进制文件出错

2、fclose函数关闭文件

一般形式:
fclose(文件指针);
例如:
fclose(fp);    //顺利关闭,则返回0,否则返回EOF(即-1)

三、文件的顺序读写

1、向文件读写一个字符——fgetc与fputc函数

读写一个字符的函数
函数名调用形式功能返回值
fgetcfgetc(fp)从fp指向的文件读入一个字符成功,带回所读字符;失败,返回文件结束标志EOF(即 -1)
fputcfputc(ch,fp)把字符ch写到文件指针变量fp所指向的文件中成功,返回值就是输出的字符;失败,返回EOF(即 -1)

a、fgetc举例

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(){
	FILE* pfRead = fopen("一段路.txt","r");
	if(pfRead==NULL){
		printf("%s\n",strerror(errno));
		return 0;
	}
	//读文件
    //向文件中放入YDL做测试
	printf("%c",fgetc(pfRead));//Y
	printf("%c",fgetc(pfRead));//D
	printf("%c\n",fgetc(pfRead));//L
	fclose(pfRead);
	pfRead = NULL;
	return 0;
}

b、fputc举例

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(){
	FILE* pfWrite = fopen("一段路.txt","w");
	if(pfWrite==NULL){
		printf("%s\n",strerror(errno));
		return 0;
	}
	fputc('y',pfWrite);
	fputc('d',pfWrite);
	fputc('l',pfWrite);
	fclose(pfWrite);
	pfWrite = NULL;
	return 0;
}

2、向文件读写一个字符串——fgets与fputs函数

读写一个字符串的函数
函数名调用形式功能返回值
fgetsfgets(str,n,fp)从fp指向的文件读入一个长度为 (n-1) 的字符串,然后在最后加一个 ‘\0’ ,存放到字符数组 str 中。若在读完 n-1 个字符之前遇到 ‘\n’ 或文件结束符 EOF ,结束输入成功,返回地址 str;失败,返回 NULL
fputsfputs(str,fp把字符串 str 写到文件指针变量 fp 所指向的文件中成功,返回 0 ;失败,返回非 0 值

a、fgets举例

//从文件中读取
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(){
	char buf[1024] = {0};
	FILE* pfRead = fopen("一段路.txt","r");
	if(pfRead==NULL){
		printf("%s\n",strerror(errno));
		return 0;
	}
	//读文件
    //将 YDL 与 一段路 分两行放入文件中
	fgets(buf,1024,pfRead);
	printf("%s",buf);//YDL
	fgets(buf,1024,pfRead);
	printf("%s\n",buf);//一段路
	fclose(pfRead);
	pfRead = NULL;
	return 0;
}

注:若输出中文为乱码,可在txt文本中选择
文件——另存为——将下方的编码改为ANSI之后再保存

b、fputs举例

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(){
	char buf[1024] = {0};
	FILE* fpWrite = fopen("一段路1.txt","w");
	if(fpWrite==NULL){
		printf("%s\n",strerror(errno));
		return 0;
	}
	fputs("Hello\n",fpWrite);
	fputs("World!\n",fpWrite);
	fclose(fpWrite);
	fpWrite = NULL;
	return 0;
}

//从键盘读取并输出
#include <stdio.h>
int main(){
	char buf[1024] = {0};
	fgets(buf,1024,stdin);//从标准输入流读取
	fputs(buf,stdout);//从标准输出流输出
	//相当以下代码:
	//gets(buf);
	//puts(buf);
	return 0;
}

3、对文件进行格式化读写——fprintf与fscanf函数

一般形式:
fprintf(文件指针,格式字符串,输出表列);
fscanf(文件指针,格式字符串,输入表列);
例如:
fprintf(fp,"%d,%5.2f",i,t);

它们的操作对象是磁盘,不是终端
若要对终端操作,只需把文件指针对应换为:stdin 与stdout 即可
但如此就与 scanf 与 printf 无异了

a、举例

#include <stdio.h>
struct S{
	int n;
	float score;
	char arr[20];
};
int main(){
	struct S a = {100,3.14f,"一段路"};
	FILE* fp = fopen("一段路1.txt","w");
	if(fp==NULL) return 0;
	//格式化写文件
	fprintf(fp,"%d %f %s",a.n,a.score,a.arr);
        //将变量(a.n)等的值,格式输出到fp所指向的文件中
	fclose(fp);
	fp = NULL;

	struct S b = {0};
	FILE* pf = fopen("一段路1.txt","r");
	if(pf==NULL) return 0;
	//格式化的输入数据
	fscanf(pf,"%d%f%s",&(b.n),&(b.score),b.arr);
        //将pf所指向的文件中的数据读入,分别放入(b.n)等变量中
	printf("%d %f %s\n",b.n,b.score,b.arr);
        //判断读入是否正确
	fclose(pf);
	pf = NULL;
	return 0;
}

b、比较(printf,fprintf,sprintf)

//sscanf函数与sprintf函数
#include <stdio.h>
struct S{
	int n;
	float score;
	char arr[20];
};
int main(){
	struct S a = {100,3.14f,"一段路"};
	struct S b = {0};
	char buf[1024] = {0};
	//把格式化的结构体a的数据转化为字符串放到buf中
	sprintf(buf,"%d %f %s",a.n,a.score,a.arr);
	printf("buf字符串为:%s\n",buf);
	//从buf中读取格式化的数据到结构体b中
	sscanf(buf,"%d%f%s",&(b.n),&(b.score),b.arr);
	printf("得到的数据为:%d %f %s\n",b.n,b.score,b.arr);
	return 0;
}

三者区别
scanf/printf——是针对标准输入流/标准输出流的,格式化输入/输出语句
fscanf/fprintf——是针对所有输入流/所有输出流的,格式化输入/输出语句
sscanf——是从字符串中读取格式化的数据
sprintf——是把格式化数据输出成(存储到)字符串

4、按二进制方式对文件进行读写——fwrite与fread函数

fread函数
size_t fread ( void * ptr, size_t size, size_t count, FILE stream );
fwrite函数
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
第一个参数 ptr:指向要写入的元素数组的指针,转换为 const void
——(参数是一个指针或者数组地址)
第二个参数 size:要写入的每个元素的大小(以字节为单位)——(这个指针或数组单个存储单元的大小)
size_t:是无符号整数类型
第三个参数 count:元素数,每个元素的大小为字节大小,size_t是无符号整数类型。——(从数组或指针中写入到文件中的字符个数) 第四个参数 stream:指向指定输出流的FILE对象的指针(文件指针)
函数返回值 :返回从数组或指针存储到文件中的字符个数

#include <stdio.h>
struct S{
	char name[20];
	int age;
	double score;
};
int main(){
	struct S a = {"张三",20,98.5};
	FILE* fp = fopen("一段路1.txt","wb");
	if(fp==NULL) return 0;
	//二进制的形式写文件
	fwrite(&a,sizeof(struct S),1,fp);
	fclose(fp);
	fp = NULL;

	struct S b = {0};
	FILE* pf = fopen("一段路1.txt","rb");
	if(pf==NULL) return 0;
	//二进制形式读文件
	fread(&b,sizeof(struct S),1,pf);
	printf("%s %d %.2lf\n",b.name,b.age,b.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

四、文件的随机读写

1、rewind函数

rewind 函数:使文件位置标记指向文件开头
void rewind ( FILE * stream );
#include <stdio.h>
int main(){
	FILE* fp1,*fp2;
	fp1 = fopen("一段路1.txt","r");//打开输入文件
	if(fp1==NULL){
		perror("fp1");//输出:fp1:出错原因
            //perror函数为检查文件打开失败的原因
            //与之前的strerror相似,但更简洁
		return 0;
	}
	fp2 = fopen("一段路2.txt","w");//打开输出文件
	if(fp2==NULL){
		perror("fp2");
		return 0;
	}
	while(!feof(fp1)) putchar(fgetc(fp1));//连续从文件1中读入字符并输出到屏幕
	rewind(fp1);//使位置标记返回文件开头
	while(!feof(fp1)) fputc(fgetc(fp1),fp2);//从文件开头读起,输出到文件2中
	fclose(fp1);fclose(fp2);
	fp1 = NULL;fp2 = NULL;
	return 0;
}

2、fseek函数

fseek函数:移动文件位置标记
调用形式:
int fseek(FILE * stream, long int offset, int origin);
说明:
fp——文件指针
offset——以字节为单位的位移量,为长整型
origin——起始点,可以为标志符(或数字)
fseek 函数中的“起始点”的表示方法
起始点名字(标志符)用数字表示
文件开始SEEK_SET0
文件当前位置SEEK_CUR1
文件末尾SEEK_END2
#include <stdio.h>
int main(){
	FILE* fp = fopen("一段路.txt","r");
        //假设文件中已放入 abcdef
	if(fp==NULL) return 0;
	//定位文件指针
	fseek(fp,2L,0);//将位置标记移到离文件开头2字节处
        //fseek(fp,2L,1);//将位置标记移到当前位置后面2字节处
        //fseek(fp,-2L,2);//将位置标记从文件末尾处,向后退2字节
        //注意:位移量不要超过文本
	//读取文件
	int ch = fgetc(fp);
	printf("%c\n",ch);//c
	fclose(fp);
	fp = NULL;
	return 0;
}

3、ftell函数

ftell函数:测定文件位置标记的当前位置
调用形式:
long int ftell(FILE * stream);

ftell函数用于获得文件当前位置指针的位置,函数给出当前
位置指针相对于文件开头的字节数
当函数调用出错时返回 -1L
#include <stdio.h>
int main(){
	FILE* fp = fopen("一段路.txt","r");
        //假设文件中已放入 abcdef
	if(fp==NULL) return 0;
	fseek(fp,2L,0);
	int ch = fgetc(fp);
	printf("%c\n",ch);//c
	//计算当前位置指针相对于文件开头的字节数
	int pos = ftell(fp);
    if(pos==-1L) printf("error!\n");
	printf("%d\n",pos);//3
	fclose(fp);
	fp = NULL;
	return 0;
}

五、文件的结束判定——feof函数

在文件读取过程中,不能用 feof 函数的返回值直接用来判断文件是否结束,而是应用于当文件读取结束时,判断是读取失败结束,还是遇到文件尾结束
1、文本文件读取是否结束,判断返回值是否为 EOF(fgetc) ,或者 NULL(fgets)
例如:
a、fgetc 判断是否为 EOF
b、fgets 判断返回值是否为 NULL
2、二进制文件的读取是否结束,判断返回值是否小于实际要读的个数(即用 fread 判断)

#include <stdio.h>
int main(){
	FILE* fp;
	fp = fopen("一段路.txt","r");
	if(fp==NULL){
		perror("fp");
		return 0;
	}
	char ch = 0;
	while((ch=getc(fp)) != EOF) putchar(ch);
	if(ferror(fp))//判断是否为读取错误而退出
		puts("\nReading error!");
	else if(feof(fp))//判断是否是到文件尾而退出
		puts("\nEnd of file");
	fclose(fp);
	fp = NULL;
	return 0;
}

资源共享:C与C++的API获取链接(点击即可进入获取)
提取码:ijjg

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;