写在前面:学习的第一门语言是Java,之前对C也了解一点,也只是了解一点,在加上长时间没有接触了,基本就只会一个Hello World了。现在由于准备升本考试,不得不从头开始学C。这里从零开始,记录C语言学习点滴。欢迎正在学习C语言的小伙伴一起学习,未来可期,一起加油!
文件结构与自定义类型typedef
文件结构FILE是C语言为了具体实现对文件的操作而定义的一个包含文件操作相关信息的结构类型。FILE类型是用typedef重命名的。FILE文件类型说明如下:
typedef struct{
short level; //缓冲区使用量
unsigned flags; //文件状态标志
char fd; //文件描述符
short bsize; //缓冲区大小
unsigned char *buffer; //文件缓冲区的首地址
unsigned char *curp; //指向文件缓冲区的工作指针
unsigned char hold; //其他信息
unsigned istemp;
short token;
}FILE;
上述定义中,文件结构本身用关键字struct进行定义,用typedef关键字吧struct结构类型重新命名为FILE。struct内部定义的成员包含了文件缓冲区的信息。
自定义类型(typedef)不是用来定义一些新的数据类型,而是将C语言中的已有类型(包括已定义过的自定义类型)重命名,用新的名词代替已有数据类型,常用于简化对复杂数据类型定义的描述。
文件类型指针
C语言中的文件操作都是通过调用标准函数来完成的。由于结构指针的参数传递效率更高,因此C语言文件操作统一以文件指针方式实现。
定义文件类型指针的格式为:FILE *fp;
其中FILE是文件类型定义符,fp是文件类型的指针变量。文件指针是特殊指针,指向的是文件类型结构。每个文件都有自己的FILE结构和文件缓冲区,FILE结构中有一个curp成员,通过fp->curp可以指示文件缓冲区中数据存取的位置。
文件处理步骤
打开文件由标准函数fopen()实现,期一般调用实现为:
fopen("文件名", "文件打开方式");
该函数有返回值。如果执行成功,函数将返回包含文件缓冲区等详细的FILE结构地址,赋给文件指针fp。否则返回一个NULL(空值)的FILE指针。
括号内包括两个参数:“文件名” 和 “文件打开方式”。两个参数都是字符串。“文件名” 指出要对哪个具体文件进行操作,一般要指定文件的路径,如果不写出路径,则默认与应用程序的当前路径相同。
文件打开方式用来确定对所打开的文件将进行什么操作。下表为文件打开方式。
使用方式 | 含义 |
---|---|
" r " | 打开文本文件进行只读 |
" w " | 建立新文本文件进行只写 |
" a " | 打开文本文件进行追加 |
" r+ " | 打开文本文件进行读 / 写 |
" w+ " | 建立新文本文件进行读 / 写 |
" a+ " | 打开文本文件进行读 / 写 / 追加 |
" rb " | 打开二进制文件进行只读 |
" wb " | 建立二进制文件进行只写 |
" ab" | 打开二进制文件进行写 / 追加 |
" rb+ " | 打开二进制文件进行读写 / 写 |
" wb+ " | 建立二进制新文件进行读 / 写 |
" ab+ " | 打开二进制文件进行读 / 写 / 追加 |
下面两种方法都以只读的方式打开abc.txt文件
fp = fopen("abc.txt", "r"); //用字符串常量表示文件,打开文件abc.txt只读
或
char *p = "abc.txt"; //用字符指针表示文件
fp = fopen(p, "r"); //打开文件abc.txt只读
执行标准函数fopen(),计算机将完成以下步骤的工作。
为保证文件操作的可靠性,调用fopen()函数时最好做一个判断,以确保文件正常打开后在进行读写。如下:
if((fp = fopen("file.txt", "r")) == NULL){
printf("打开文件失败!");
exit(0);
}
其中exit(0)是系统标准函数,作用是关闭所有打开的文件,并终止程序的执行。参数0表示程序正常结束。
一旦文件经过fopen()正常打开,对该文件的操作方式就被确定,并且直至文件关闭都不变,即若一个文件按 r 方式打开,则只能对该文件进行读操作,而不能进行写入数据操作。
C语言允许同时打开多个文件,不同文件采用不同文件指针指示,但不允许同一个文件在关闭前再次被打开。
关闭文件通过调用标准函数fclose()实现,其一般格式为:fclose(文件指针);
该函数将返回一个整数,若该函数为0表示正常关闭文件,否则表示无法正常关闭文件,所以关闭文件也应该使用条件判断:
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
关闭文件操作除了强制把缓冲区中的数据写入磁盘外,还将释放文件缓冲区单元的FILE结构。
C语言标准库stdio.h中提供了一系列文件的读写操作函数,常用的函数如下:
1、字符方式文件读写函数fgetc()和fputc()
对于文本文件,存取的数据都是ASCII码字符文本,使用这两个函数读写文件时,逐个字符地址进行文件读写。
fgetc()函数实现从fp说指示的磁盘文件读入一个字符到ch。函数调用格式:
ch = fgetc(fp);
该函数与getchar()函数功能类似,getchar()从键盘上读入一个字符。
fputc()函数把一个字符ch写到fp说指向的磁盘文件上。函数调用格式:
fputc(ch, fp);
函数返回值若写文件成功为ch,若写文件失败则为EOF。该函数同putchar()函数类似,putchar(ch)把ch显示在屏幕上。EOF是符号常量,其值为-1。
fgetc()和fputc()函数读写案例(将file.txt文件内存备份到file1.txt文件中):
#include
#include
int main(){
//定义文件指针
FILE *fp, *fp1;
char ch;
//打开文件, 读出数据
if((fp = fopen("file.txt", "r")) == NULL){
printf("打开文件失败!");
exit(0);
}
//打开文件,写入数据
if((fp1 = fopen("file1.txt", "w")) == NULL){
printf("打开文件失败!");
exit(0);
}
//复制数据,file.txt文件读取,写入file1.txt文件
while(!feof(fp)){
ch = fgetc(fp); //从fp所指示的文件读取一个字符
printf("%c", ch);
if(ch != EOF)
fputc(ch, fp1); //将字符ch写入fp1指示的文件
}
//关闭文件
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
if(fclose(fp1)){
printf("关闭文件失败");
exit(0);
}
return 0;
}
运行程序后,会在源程序所在目录下产生file1.txt文件,打开文件,内容与file.txt的内容完全相同。如下:
程序实现了复制文件功能,设计对两个文件的操作,所以程序定义两个EILF结构类型指针,并分别指向文件所打开的文件file.txt和file1.txt。
while(!feof(fp)){
ch = fgetc(fp); //从fp所指示的文件读取一个字符
printf("%c", ch);
if(ch != EOF)
fputc(ch, fp1); //将字符ch写入fp1指示的文件
}
在上述代码中,调用函数feof()来检测fp所指示的文件的位置是否到了文件末尾。打开文件时fp指针指向文件首部,每次调用fgetc()函数成功执行后,fp会自动向后移动一个位置。只要 !feof(fp) 结果为真,就说明fp指针还没有指向文件末尾,程序会反复从危机file.txt中读取字符,并将该字符写入文件file1.txt。
fgetc()函数在读到有效字符时,会向后移动指针,若读到文件末尾,则会读到一个无效的字符,返回EOF。
2、字符串方式文件读写函数fgets()和fputs()
这两个函数以字符串的方式来对文本文件进行读写。读写文件时一次读取或写入的是字符串。
fputs()函数是用来指定的文本文件写入一个字符串,调用格式为:
fputs(s, fp);
其中 s 是要写入的字符串,可以是字符数组名、字符型指针变量或字符串常量,fp是文件指针。该函数把 s 写入文件时,字符串 s 的结束符’ \0 '不写入文件。罗函数执行完成,则函数返回所写的最后一个字符;否则,函数返回EOF。
fgets()函数用来从文本文件中读取字符串,调用格式为:
fgets(s, n, fp);
其中 s 可以是字符数组名或字符指针(指向字符串的指针),n是指定读入的字符个数,fp是文件指针。函数调用时,最多读取n-1个字符(会在读取的字符后面自动添加一个’ \0 '字符)。
fgets()读取文件
#include
#include
int main(){
//定义文件指针
FILE *fp;
char ch[10];
//打开文件
if((fp = fopen("file.txt", "r+")) == NULL){
printf("打开文件失败!");
exit(0);
}
//读取字符串
fgets(ch, 3, fp);
printf("%s\n", ch);
//关闭文件
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
return 0;
}
fgets()函数读取file文件中的第一行的两个字符,效果如下:
fputs()函数写入字符串到文件
#include
#include
int main(){
//定义文件指针
FILE *fp;
char ch[10] = "ffff";
//打开文件
if((fp = fopen("file.txt", "a")) == NULL){
printf("打开文件失败!");
exit(0);
}
//写入字符串
fputs(ch, fp);
//关闭文件
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
return 0;
}
fputs()函数将字符串 “ffff” 写入到文件中,运行程序后,file.txt文件内容如下(字符串追加在原有内容后面,根据打开文件方式确定是追加在文件最后还是文件缓冲区指针位置):
3、格式化方式文件读写函数fscanf()和fprintf()
前面经常用到函数scanf()和函数printf(),分别用来从键盘上读入和向屏幕上输出数据。fscanf()用于从文件中按照给定的控制格式读取数据,而fprintf()用于按照给定的控制格式向文件中写入数据。如果是读文件,会从文件中按改定的控制格式读取数据保存到变量;若是写文件,这按格式写入数据到文件。函数调用格式为:
fscanf(文件指针,格式字符串,输入表);
fprintf(文件指针,格式字符串,输出表);
例如:
FILE *fp;
int n;
fp = fopen("a.txt", "r");
fscanf(fp, "%d %f", &n, &x);
表示从文件a.txt分别读入整型数到变量n、浮点数到变量x。
【注】文件中必须在读取类型的数据,每个数据之间可以空格隔开
FILE *fp;
int n;
float x;
fp = fopen("b.txt", "w");
fprintf(fp, "%d %f", n, x);
表示把变量n和x的数值写入文件b.txt中。
fscanf()和fprintf()函数的基本使用
#include
#include
int main(){
//定义文件指针
FILE *fp;
int i, age;
char name[10];
//打开文件, 读出数据
if((fp = fopen("file.txt", "r+")) == NULL){
printf("打开文件失败!");
exit(0);
}
//从文件中读取数据
for(i = 0; i < 2; i++){
fscanf(fp, "%s %d", &name, &age);
printf("%s\t%d\n", name, age);
}
//写入数据到文件中
int a = 18;
char name2[10] = "\nabc";
fprintf(fp, "%s %d", name2, a);
//关闭文件
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
return 0;
}
file.txt文件初始数据如下:
先使用fscanf()函数读取文件中数据,在控制台输出。之后在写入一行数据到文件中。此时缓冲区指针在最后,所以数据直接添加在文件最后。上述程序执行完成后控制台和文件中的内容如下:
4、数据块方式文件读写函数fread()和fwrite()
fread()和fwrite()用于读写数据块(指定字节数量),可用来读写一组数据,如一个数组元素、一个结构变量的值等。这两个函数多用于读写二进制文件。
函数fread()用于从二进制文件中读入一个数据块到变量。函数fwrite()用于向二进制文件中写入一个数据块。这两个函数的调用格式为:
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
其中buffer是一个指针,在函数fread中,它表示存放输入数据的首地址;在函数fwrite中,它表示存放输出数据的首地址。size表示数据块的字节数。count表示要读写的数据块数。fp表示文件指针。例如:
fread(fa, 4, 5, fp);
从fp所指向的文件中,每次读4个字节(一个实数)送入数组fa中,连续读5次,即读5个实数到fa中。
fread()和fwrite()函数使用案例
以二进制方式读写用户信息文件file.txt,输入5位用户的用户名密码,写入文件,然后读取所有用户信息并显示。
#include
#include
#include
#define SIZE 5 //用户个数
struct sysuser{ //用户信息结构
char username[20];
char password[8];
};
int main(){
//定义文件指针
FILE *fp;
int i;
struct sysuser u[SIZE], su[SIZE], *pu = u, *psu = su;
//打开文件, 建立二进制文件进行读 / 写方式
if((fp = fopen("file.txt", "wb+")) == NULL){
printf("打开文件失败!");
exit(0);
}
//输入size个用户学校,保存到结构数组u中
for(i = 0; i < SIZE; pu++, i++){
printf("请输入第 %d 个用户名和密码:", (i+1));
scanf("%s %s", pu->username, pu->password); //输入用户名和密码
}
pu = u;
fwrite(pu, sizeof(struct sysuser), SIZE, fp); //写入二进制文件
rewind(fp); //将指针重新定位到文件首
//读取size条数据到psu指向的结构数组
fread(psu, sizeof(struct sysuser), SIZE, fp);
//输出读取的数据
for(i = 0; i < SIZE; i++, psu++){
printf("%s\t%s\n", psu->username, psu->password);
}
//关闭文件
if(fclose(fp)){
printf("关闭文件失败");
exit(0);
}
return 0;
}
运行效果如下:
程序中定义了一个结构类型struct sysuser,定义了两个结构数组u和su以及两个结构指针变量pu和psu。pu指向u,psu指向su。程序中的fopen()语句以读写方式打开二进制文件file.txt,输入SIZE个用户信息数据之后,写入该文件中,然后把文件内部位置指针重新定位移动到文件首,读入SIZE个用户信息数据后,输出显示,rewind()函数用来重新定位文件指针到文件首。
由于初学C语言,上述内容如有错误地方,恳请各位大佬指出!