——一般来说,文件是指一组相关数据的有序集合。文件通常是驻留在外部介质(如磁盘)上的,在使用时才调入内存。程序执行时,所有的数据都存储在内存中,这些数据只能临时存放而不能永久保存,要想永久保存就要把数据以文件形式存储在外存储器中。每个文件都有一个名字,操作系统以文件为单位对数据进行管理。
C语言从不同的角度对文件进行分类:
①从用户的角度,文件可分为普通文件和设备文件。
普通文件是保存在磁盘或其他外部介质上的一个有序数据集。源文件、目标文件、可执行文件等都是普通文件。
设备文件是指显示器、打印机、键盘等外部设备。C语言把外部设备也看作是一个文件来进行管理,把其输入、输出等同于对磁盘文件的读和写。例如:键盘被默认为标准输入文件,屏幕被默认为标准输出文件。
②根据数据的编码方式,可分为文本文件和二进制文件。
文本文件是按照数据在内存中的存储形式放到磁盘上的。例如,整数12345678存储时被视为‘1’、‘2’、...‘8’,8个字符占8个字节。
二进制文件是按照数据在内存中的存储形式放到磁盘上的。例如,整数12345678,在内存中按二进制形式存放,占4个字节。
二进制VS文本
文件类型 | 文件优点 | 文件劣势 |
二进制 | 程序读写快 | 人类读写困难,而且不跨平台 int(数据类型)大小不一致,大小端问题 |
文本 | 便于人类读写,而且跨平台 | 程序输入输出需要格式化,开销大 |
目前C语言使用的文件系统分为缓冲文件系统(标准I/O)和非缓冲文件系统(系统I/O)。
←缓冲文件系统
#include<stdio.h>
#include<stdlib.h>
int main(){
FILE *fp;
fp=fopen("f1.txt","w");
fprintf(fp,"Hello World!");
fclose(fp);
return 0;
}
*fp是文件指针;每一个被使用的文件都要在内存中开辟一个区域,用来存放有关信息,包括文件名称、文件状态和文件当前位置等。这些信息被保存在一个结构变量中,该结构类型被系统定义为FILE,放在“stdio.h”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;
fopen函数用来打开一个文件,其调用的一般形式为:
文件指针名 = fopen(文件名字符串,使用文件方式字符串);
fp=fopen("f1.txt","w");
f1.txt默认在c工程所在的文件夹中。“w”表示建立只写文件,如果不存在新建一个并写入,若存在,直接写入覆盖文件原来内容。
输入/输出重定向函数freopen()
freopen("in.txt","r",stdin);
把标准输入流stdin重定向到in.txt中,在scanf的时候,不在从键盘输入文件中读取,而是从in.txt文件中读取。
freopen("out.txt","w",stdout);
把可执行程序的标准输出或标准错误输出重新定向到指定的out.txt文件中。把stdout重定向到out.txt中,输出结果不会显示到标准输出设备上,而是保存到out.txt中。
重定向文件算a+b,结果保存在out.txt文件中:
int main(){
int a,b;
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
while(scanf("%d%d",&a,&b)!=EOF){
printf("%d\n",a+b);
}
fclose(stdin);
fclose(stdout);
return 0;
}
字符读/写函数fgetc()和fputc()
①fputc函数是将一个字符写到磁盘文件中,同时移动读写位置指针到下一个写入位置。
fputc(字符型变量,文件指针);
如果写入成功,返回该字符,失败,返回EOF(-1)
②fgetc函数从磁盘中读取一个字符,无出错返回值。
fgetc(文件指针);
int main(){
FILE *fp;
char ch;
if(!(fp=fopen("f2.txt","w")))
{
printf("can not open this file\n");
return;//exit(0)
}
for(;(ch=getchar())!='@';)
fputc(ch,fp);
fclose(fp);
if(!(fp=fopen("f2.txt","r")))
{
printf("can not open this file\n");
return;//exit(0)
}
for(;(ch=fgetc(fp))!=EOF;)
putchar(ch);
fclose(fp);
return 0;
}
字符串读/写函数fgets()和fputs()
①fputs函数用来向指定的文件写入一个字符串
fputs(字符数组,文件指针);
其中字符数组要写入的字符串,可以是一个字符串常量、或字符指针变量名。需要注意的是结束符'\0'不写入文件,若写成功,返回一个非负数;否则,返回EOF。
②fgets函数从文件中读取字符串,成功,返回字符串,失败,返回空指针
fgets(字符数组,字符个数(字符串长度),文件指针);字符串长度如果用strlen函数,需要加一,即strlen(string)+1,因为strlen是不统计'\0'的,用sizeof(string)不用加一。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEN 100
int main(){
FILE *fp;
char string[LEN];
if(!(fp=fopen("f2.txt","w")))
{
printf("can not open this file\n");
return;//exit(0)
}
printf("Input a string:");
gets(string);
fputs(string,fp);
fclose(fp);
if(!(fp=fopen("f2.txt","r")))
{
printf("can not open this file\n");
return;//exit(0)
}
fgets(string,sizeof(string),fp);
printf("Output the string:");
puts(string);
fclose(fp);
return 0;
}
格式化文件读/写函数fscanf()和fprintf()
fscanf(文件指针,格式字符串,输入表);
fprintf(文件指针,格式字符串,输出表);
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEN 100
struct hero{
char name[10],petname[10],id[12];
int age;
}Hero[LEN];
int main(){
FILE *fp,*fp1;
int i,count=0;
fp=fopen("f1.txt","r");
if(fp==NULL){
printf("Can not read data from file f1!\n");
return;
}
fp1=fopen("f2.txt","w");
if(fp1==NULL){
printf("can not write data to file f2!\n");
return;
}
for(i=0;(fscanf(fp,"%s%s%d%s",Hero[i].name,Hero[i].petname,&Hero[i].age,Hero[i].id))!=EOF;i++){count++;}
for(i=0;i<count;i++)
{
fprintf(fp1,"%s %s %d %s\n",Hero[i].name,Hero[i].petname,Hero[i].age,Hero[i].id);
}
for(i=0;i<count;i++){
printf("%s %s %d %s\n",Hero[i].name,Hero[i].petname,Hero[i].age,Hero[i].id);
}
fclose(fp);
fclose(fp1);
return 0;
}
数据块读/写函数fread()和fwrite()
fread(数据区首地址,每次读取的字节数,读取次数,文件指针);
fwrite(数据区首地址,每次写入的字节数,写入次数,文件指针);
数据存储区首地址可以是数组名、结构变量或结构指针。如果操作成功,返回1;失败,返回0。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEN 100
struct hero{
char name[10];
char petname[10];
int age;
char id[12];
}Hero[LEN];
int main(){
FILE *fp,*fp1;
int i,count=0;
fp=fopen("f1.txt","r");
if(fp==NULL){
printf("Can not read data from file f1!\n");
return;
}
fp1=fopen("f2.txt","w");
if(fp1==NULL){
printf("can not write data to file f2!\n");
return;
}
fread(Hero,sizeof(Hero[0]),4,fp);
fwrite(Hero,sizeof(Hero[0]),4,fp1);
fclose(fp);
fclose(fp1);
return 0;
}
fseek(文件指针,字节单位(整数),开始位置);
int main(){
FILE *fp,*fp1;
char t[20];
char s[]="How are you!";
if((fp=fopen("f1.txt","w"))==0){
printf("File open error!\n");
return;
}
fwrite(s,strlen(s),1,fp);
fclose(fp);
if((fp1=fopen("f1.txt","r"))==0){
printf("File open error!\n");
return;
}
fseek(fp1,3,0);
fread(t,7,1,fp1);
t[7]='\0';
printf("\n%s\n",t);
fclose(fp1);
return 0;
}
⭐其中,fp,fp1不能用一个,一个是写入的文件指针,一个是读出的文件指针,不然用一个的话,会输出不了正常的字符串。