文件操作读写
1 文件处理原理及基本概念
C语言的文件处理功能,大体上分为两种:一种是设置缓冲区,另一种是不设置缓冲区。因为不设置缓冲区的方法直接对磁盘进行操作,速度较慢,并且由于不是C的标准函数,跨平台操作时容易出问题。本文只介绍设置缓冲区的文件处理方式:
当使用包含在头文件stdio.h中的标准I/O函数时,系统会自动设置缓冲区,并通过数据流来读写文件。当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据。
1.1 相关概念
数据流:指程序与数据的交互是以流的形式进行的。进行C语言文件的存取时,都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。
缓冲区:指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。
1.2 文件类型
介绍下文本文件和二进制文件,
文本文件:是以字符编码的方式进行保存的。
二进制文件:将内存中数据原封不至文件中,如果以记事本打开,只会看到一堆乱码。二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据。
2 文件操作函数
2.1 打开文件
您可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE 包含了所有用来控制流的必要的信息。下面是这个函数调用的原型:
FILE *fopen( const char * filename, const char * mode );
filename 是字符串,代表文件名。Mode为文件的打开模式。何为打开模式?下面列出:
模式 | 描述 |
r | 打开一个已有的文本文件,允许读取文件。 |
w | 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。 |
a | 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。 |
r+ | 打开一个文本文件,允许读写文件。 |
w+ | 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。 |
a+ | 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。 |
注:打开二进制文件的模式与打开文本文件是一样的,不同的是模式名称里面多一个字母'b’,以表示以二进制形式打开文件。
举例说明:
FILE *fp = NULL;
fp = fopen("/tmp/test.txt", "w+");
2.2 关闭文件
关闭文件,请使用 fclose() 函数。函数的原型如下:
int fclose( FILE *fp );
如果成功关闭文件,fclose( ) 函数返回零,如果关闭文件时发生错误,函数返回 EOF。这个函数实际上,会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。EOF 是一个定义在头文件 stdio.h 中的常量。
例子:
FILE *fp = NULL;
fp = fopen("/tmp/test.txt", "w+");
fclose(fp);
2.3 读写文本文件
(1) 按照字符读写
下面是从文件读取单个字符函数:
int fgetc( FILE * fp );
函数fgetc()从fp所指向的输入文件中读取一个字符。返回值是读取的字符,如果发生错误则返回EOF
下面是写入单字符的函数:
int fputc( int c, FILE *fp );
函数fputc()把参数c的字符值写入到fp所指向的输出流中。如果写入成功,它会返回写入的字符,如果发生错误,则会返回EOF。
(2) 按照字符串读写
下面是从文件读取字符串函数
char *fgets( char *buf, int n, FILE *fp );
函数 fgets() 从 fp 所指向的输入流中读取 n - 1 个字符。它会把读取的字符串复制到缓冲区,并在最后追加一个 null 字符来终止字符串。
例子:fgets(buff, 255, fp);
下面是从文件写入字符串函数:
int fputs( const char *s, FILE *fp );
举例说明:
fputs("YangLaoShi zui shuai", fp)
函数 fputs() 把字符串 s 写入到 fp 所指向的输出流中。如果写入成功,它会返回一个非负值,如果发生错误,则会返回 EOF
(3)格式化存取(重点掌握):
int fscanf(FILE *fp,const char *format)
int fprintf(FILE *fp,const char *format)
它们与printf和scanf函数相仿,都是格式化读写函数,用法也相似。不同之处在于fscanf和fprintf函数是将fp指向的文件作为缓冲区,进行输入输出。
例子:
FILE * fp = fopen("txt_out.txt","w");
例如我们想写入成绩:
fprintf(fp, "%-20.20s %-20.20s %-20.20s %-20.20s %-20.20s %-20.20s %-20.20s\n", "学号", "姓名", "性别", "C语言", "语文", "数学", "英语");
while (i < num)
{
fprintf(fp, "%-20s %-20s %-20s %-20d %-20d %-20d %-20d\n", Pst[i].studentid, Pst[i].name, Pst[i].sex, Pst[i].Cscore, Pst[i].Lscore, Pst[i].Mscore, Pst[i].Escore);
++i;
}
或者获取成绩:
fp = fopen("./student.txt", "r")
fscanf(fp, "%20s %20s %20s %20s %20s %20s %20s", Firstline[0], Firstline[1], Firstline[2], Firstline[3], Firstline[4], Firstline[5], Firstline[6]);
while (fscanf(fp, "%20s %20s %20s %20d %20d %20d %20d", Pst[i].studentid, Pst[i].name, Pst[i].sex, &Pst[i].Cscore, &Pst[i].Lscore, &Pst[i].Mscore, &Pst[i].Escore) != EOF)
{
i++;
}
具体细节请自行百度
2.4 读写二进制文件
当要求一次存取一组数据(如,一个数组、一个结构体变量的值),fread和fwrite函数可以解决该类问题。它们的调用形式一般为:
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
buffer:对于fread来说,指的是读入数据的存放地址;对于fwrite来说,是要输出数据的地址。
size:读写数据时,每笔数据的大小
count:读写数据的笔数
fp:文件指针
例子:
fread(pos,sizeof(double),200,fid);
fwrite(pos,sizeof(double),1,fid);//pos为数组名
2.5练习
我们结合所学知识写出部分代码:
//Txt写入
void TxtWrite()
{//准备数据int index[50] ;double x_pos[50], y_pos[50];for(int i = 0; i < 50; i ++ ){index[i] = i;x_pos[i] = rand()%1000 * 0.01;y_pos[i] = rand()%2000 * 0.01;}//写入FILE * fid = fopen("txt_out.txt","w");if(fid == NULL){printf("写出文件失败!\n");return;}for(int i = 0; i < 50; i ++ )fprintf(fid,"%03d\t%4.6lf\t%4.6lf\n",index[i],x_pos[i],y_pos[i]);fclose(fid);
}//Txt读取
void TxtRead()
{FILE * fid = fopen("txt_out.txt","r");if(fid == NULL){printf("打开%s失败","txt_out.txt");return;}char line[1024];memset(line,0,1024);while(!feof(fid)){fgets(line,1024,fid);printf("%s\n", line); //输出}fclose(fid);
}//二进制文件写入
void DataWrite()
{//准备数据double pos[200];for(int i = 0; i < 200; i ++ )pos[i] = i;//写入FILE *fid;fid = fopen("binary.dat","wb");if(fid == NULL){printf("写出文件出错");return;}fwrite(pos, sizeof(double), 200, fid);fclose(fid);
}//二进制文件读取
void DataRead()
{FILE *fid;
double pos[200];fid = fopen("binary.dat","rb");if(fid == NULL){printf("读取文件出错");return;}fread(pos,sizeof(double),200,fid);for(int i = 0; i < 200; i++)printf("%lf\n", pos[i]);fclose(fid);
}