C语言文件入门基础
9——文件
程序处理的数据是如何进入计算机内部的,计算机程序计算的结果又要输出到那里去,在c语言的程序的文件使用,这时的输入与输出的设备就针对文件系统了。
9.1 各类的定义
文件:所谓文件是一般指存储作外部介质(如磁盘,磁带)上数据的集合,操作系统是以文件为单位对数据进行管理的,
流:在c语言的标准库中,提供了一套流操作函数,其中包括流的创建(打开文件),撤销(关闭文件),对流的读写(实际上是流对文件的读和写),以及一些与文件操作相关的函数。
c程序启动时会自动创建3个流:标准输入流(stdin),标准输出流(stdout)和标准输出错误流(stderr).
文件分类:
- 文本文件:每个字符均与ASCII代码存储,占一个字符。
- 二进制文件:由二进制字节代码组成
9.2 文件使用
程序运行时文件或者流时,系统就为此文件开辟一个FILE类型变量,程序使用几个文件,系统就开辟几个FILE类型变量。
typedef struct
{
short level; //fill/empty level of buffer
unsigned flags; //文件状态标志
char fd; //文件描述符
unsigned char hold; //Ungetc char if no buffer
short bsize; //缓冲大小
unsigned char * buffer; //数据传输指针
unsigned char * curp; //当前激活指针
unsigned istemp; //临时文件指示器
short token; //用于合法性校和
} FILE;
9.3文件的打开与关闭
9.3.1 fopen函数
文件打开操作通过标准库中函数fopen完成,原型为
FILE *fopen(const char *filename,const char *mode);
当文件打开的操作不能正常完成时,函数fopen()返回空指针(0),并把错误存入errno中。
文件打开方式
模式 | 含义 |
---|---|
r | 打开一个文本文件只读 |
w | 打开一个文本文件只写 |
a | 打开一个文本文件尾部追加 |
rb | 打开一个二进制文件只读 |
wb | 打开一个二进制文件只写 |
ab | 打开一个二进制文件追加 |
r+ | 打开一个文本文件可读/写 |
w+ | 创建一个文本文件只读/写 |
rb+ | 打开一个二进制文件读写 |
wb+ | 打开一个二进制文件读写 |
ab+ | 打开一个二进值文件读写 |
!注意
w+ 打开文件并读写 1. 文件存在,则清空(也即写入空); 2. 文件不存在,则创建文件 ; 3. 文件流定位到开始位置,
所以read() 会得到空。 r+ 打开文件并读写 1. 文件存在,打开文件,文件指针定位到文件开始位置; 2. 文件不存在,
则报错文件不存在。 a+ 打开文件并读添 1. 文件存在,打开文件,文件指针定位到文件开始位置,但不清空;2.
文件不存在,创建文件; 3. 打开后读取时,在文件开头位置,4. 写入时,添加到文章末尾,并且指针位于添加后的末尾,所以再次读取会乱码。
二进制文件类似
9.3.2关闭函数fclose
该函数主要完成关闭流的所有工作。正常完成时返回0,出问题时返回EOF,
原型为:
int fclose (FILE * stream)
fclose正常完成时返回0,出现问题时返回值为EOF
9.3.3 基本过程
FILE * fp;
fp=fopen("路径","打开方式");//切记根据文件与流的关系,选择相应的模式
if(fp==NULL) //判断文件打开是否成功
{
//不成功的操作
}
fclose(cp);
9.4 文件的读写操作
9.4.1 判断文件是否结束feof()
函数feof()即可判断文件是否到了结束标志。
函数原型为:
int feof(FILE * stream);
函数的返回值为非0的数,则说明文件指针以指向文件的结尾。
9.4.2 读写字符函数fgetc与fputc
fgetc,从文件当前流所在位置获取一个字符,并将文件指针指示器移到下一个字符处,如果已经到了文件尾,则返回一个EOF,函数原型为:
int fgetc(FILE * stream)
fputc函数完成对字符ch的值写入所指定的文件中,并将文件指针后移一位,fputc函数的返回值是所写入写入字符的值,出错返回EOF
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
int ch;
if((fp=fopen("e:\\wenjian\\test.txt","w"))==NULL)
{
printf("Failure to open demo.txt!\n");
exit(0);
}
while((ch=getchar())!= '\n')
fputc(ch,fp);
fclose(fp);
return 0;
}
9.4.3 读写字符串函数fgets和fputs
c语言中还提供对字符串操作的函数
- fgets从文件中读取num-1个字符,并把它们放入str所指向的字符数组中。
函数形式:
char *fgets(char * str, int num,FILE * stream);
- fputs将str指向的文件写入流文件
int fputs(char *str,FILE *stream);
9.4.5 格式化输入,输出函数fscanf()和fprintf()
类型用法跟printf与scanf的用法类似,而这上述两函数只需要在前面加入文件指针,请看函数原型
int fscanf(FILE * stream,char *format,arg_list);
int fprintf(FILE * stream,char *format,arg_list);
实例介绍使用
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct stu
{
char name[15];
char num[6];
float score[2];
}student;
int main()
{
FILE *fp;
int i;
if((fp=fopen("e:\\wenjian\\test.txt","w"))==NULL)
{
printf("cannot open file");
exit(0);
}
printf("input data:\n");
for(i=0;i<2;i++)
{
scanf("%s %s %f %f\n",student.name,student.num,&student.score[0],&student.score[1]);
fprintf(fp,"%s %s %7.2f %7.2f",student.name,student.num,student.score[0],student.score[1]);
}
fclose(fp);
if((fp=fopen("e:\\wenjian\\test.txt","r"))==NULL)
{
printf("cannot open file");
exit(0);
}
printf("output data:\n");
while(fscanf(fp,"%s %s %f %f",student.name,student.num,&student.score[0],&student.score[1]) != EOF)
{
printf("%s %s %7.2f %7.2f\n",student.name,student.num,student.score[0],student.score[1]);
}
fclose(fp);
return 0;
}
9.4.6 块读写函数fread()和fwrite()
由于复杂的数据类型无法以整体形式向文件写入或从文件读出,C语言提供成块的读写方式来操作文件,使其数组或结构体等类型可以进行一次性的读写。函数的原型:
size_t fread(void * pointer,size_t size,size_t num ,FILE *stream);
size_t fwrite(void * pointer,size_t size,size_t num ,FILE *stream);
其中size_t是c语言定义的无符号的整型。pointer指向数据的起始位置
%%在此准备一个实例供大家观看,块存储函数的具体应用,使得大家更深入的理解
*** 使用文件存储对班级学生进行高考基本成绩信息的存储与输出,学生的基本信息有学号,姓名,年龄和高考成绩。***
#include <string.h>
#include <stdio.h>
#define N 2 //定义班级学生个数
void write(); //完成对文件的写入操作
void read(); //完成对文件的读出操作
struct student{
char name[8];
int num;
int age;
float score;
}stu[N];
int main()
{
int i;
for (i=0;i<N;i++)
{
scanf("%s %d %d %f",stu[i].name,&stu[i].num,&stu[i].age,&stu[i].score);
}
write();
printf("press any key to show data from file\n");
getchar();
read();
return 0;
}
void write()
{
FILE *fp;
int i;
if((fp=fopen("e:\\wenjian\\test.txt","wb"))==NULL)
{
printf("cannot open file\n");
return ;
}
for(i=0;i<N;i++)
{
if(fwrite(&stu[i],sizeof(struct student),1,fp)!=1)
{
printf("file write error\n");
}
}
fclose(fp);
}
void read()
{
FILE *fp;
int i;
if((fp=fopen("e:\\wenjian\\test.txt","rb"))==NULL)
{
printf("cannot open file\n");
return ;
}
for (i=0;i<N;i++)
{
if(fread(&stu[i],sizeof(struct student),1,fp)==1)
{
printf("%-10s%8d%6d%12.2f\n",stu[i].name,stu[i].num,stu[i].age,stu[i].score);
}
else{
printf("file read error\n");
break;
}
}
fclose(fp);
}
9.5 文件指针的定位
函数名 | 函数原型 | 功能 |
---|---|---|
fseek | int fseek(FILE * stream,long offset,int origin); | 根据origin的值移动文件指针 |
rewind | int rewind(FILE * stream); | 重返文件起始位置 |
ftell | int ftell(FILE * stream); | 返回文件指针的当前位置 |
符号常量 | 值 | 含义 |
---|---|---|
SEEK_SET | 0 | 从文件开头计算 |
SEEK_CUP | 1 | 重返文件起始位置 |
SEEK_END | 2 | 从文件的末尾计算 |
例如:fseek(fp,5L,0);将文件指针从文件头向下移动五字节
fseek(fp,5L,2):将文件指针从文件末尾向上移动五字节
9.6 出错检测
在使用各种输入,输出函数时,如果出现错误,除了可以由返回值表现外,还可以使用ferror函数检查
函数原型:
int ferror(FILE * stream);
注意:对同一文件每一次调用输入、输出函数。均产生一个新的ferror函数值,因此在调用一个输出、输入函数,应立即检查ferror函数的值,否则信息会丢失,在执行fopen函数,ferror函数的初始值自动置为0。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *stream;
stream=fopen("e:\\text.txt","w");
fgetc(stream);
if(ferror(stream)){
printf("Error reading from text.dat");
clearerr(stream); //重置错误标志并将指针置于EOF
}
fclose(stream);
return 0;
}