文件
有一点感觉很重要,那就是用a或a+等方式打开文件,然后紧接着用ftell(fp);获取文件位置指针,发现都是0,但是发现当第一次写的时候文件位置会移到文件尾。
读文件
出错返回NULL
FILE *fp=fopen("D:\\demo.txt","r");
打开方式
1.如何没有b,则是以文本方式打开文件
2.凡是以r打开文件,文件必须存在
3.+是读/写
r 读方式打开 只允许读,不允许写
r+ 读/写文件 允许读和写
rb+ 读/写文件 允许读和写
rt+ 读/写文件 允许读和写
w 只写方式打开 文件存在则清0,不存在创建文件
w+ 读/写方式打开 文件存在则清0,不存在创建文件
wb 以只写方式打开或创建文件 只允许写
wb+ 以读/写方式打开或创建文件 允许读和写
wt+ 以读/写方式打开或创建文件 允许读和写
a 以追加方式打开只写文件 存在则写入的数据会追加到文件尾,不存在创建
a+ 以追加方式打开读/写文件 存在则写入的数据会追加到文件尾,不存在创建
ab+ 以读写方式打开 允许读或在文件尾追加
at+ 以读/写方式打开 允许读或在文件尾追加
把一个文本文件读入内存时,要将ASCII码转换成二进制码,而把文件以文本方式写入磁盘时,也要把二进制码转换成ASCII码,因此文本文件的读写要花费较多的转换时间。对二进制文件的读写不存在这种转换。
DOS和Windows系统使用CRLF(0x0D 0x0A)\r\n双字节作为文本文件换行符,而Unix文本文件的换行符只有一个字节LF(0x0A)\n。在C语言中,也是以LF即'\n'为换行符。
在Unix和其他一些系统中,沒有文本方式和二进制方式的区分,使不使用'b'标志都是一样的。
关闭文件
成功返回0,失败返回非0
int fclose(FILE *fp);
以字符方式读写文件(fgetc()和fputc())
int fgetc(FILE *fp); //成功返回读取到的字符,失败返回EOF(EOF不绝对是-1,这要看编译器的实现)
不读取文件的最后结束标志,用putc(ch,stdout);或putchar(ch);输出最后没有换行
这里我们可以借助while((fp=fgetc(fp))!=NULL){ putchar(ch); } 来获取读到字符,但是由于fgetc()读取失败也是返回EOF,无法判断是否读取到文件尾,我们可以通过feof()和ferror()来进行判断是否真的读取到文件尾。
int feof(FILE *fp); int ferror(FILE *fp); //正确都是返回0,否则返回非0
使用示例:
if(ferror(fp))
printf("文件出错!\n");
else
printf("文件成功!\n");
int putc(int ch,FILE *fp); //成功返回要写入的字符,失败返回EOF
使用示例:
#include<stdio.h>
int main(void)
{
FILE *fp;
char ch;
fp=fopen("words.txt","wt+");
puts("请输入一个字符串");
while((ch=getchar())!='\n') //这里发现可以录入汉字“你好”到fp所指的文件中
{
putc(ch,fp);
}
return 0;
}
然后把上面的程序改为
fopen("words.txt","r");
while((ch=getc(fp))!=EOF)
{
putc(ch); //这里发现,是可以输出文件中的中文的
}
以字符串的方式读取文件
在c语言中没有按行读取文件的函数,可以把fgets()中的参数n设置的足够大,以至于可以读取一行的数据来代替读取一行的数据。
fgets()函数遇到换行会将换行读取到字符串中,然后在字符串末尾添加\0;而gets()函数会忽略换行。
char *fgets(char *str,int n,FILE *fp); //读取成功返回字符串的首地址,即str,否则返回NULL。读取到的字符串末尾自动添加\0,也 就是说实际读取到的是n-1个字符。遇到\n则自动结束。
示例:
#include<stdio.h>
int main(void)
{
FILE *fp;
char ch[40];
fp=fopen("words.txt","r");
while(fgets(ch,40,fp)!=NULL) //这里发现如果把40改为3,仍然可以输出第2个字符之后的数据,出现数组越界,但 是在vc6.0下没有报错
{
fputs(ch,stdout); //这里一样可以一行一行输出文件中的内容
}
return 0;
}
int fputs(char *str,FILE *fp); //写入成功返回非负,否则返回EOF
多行读取
size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );
count是数据块的块数
size是读取的字节数
理论上,每次读写 size*count 个字节的数据
size_t 是在 stddef.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。
返回成功读写的块数,也即 count。如果返回值小于 count:
- 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
- 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。
fwrite()/fread() 函数直接操作字节,建议使用二进制方式打开文件。
示例1如下:
#include<stdio.h>
#define N 5
int main(void)
{
//从键盘录入的数据放入a,从文件读取的数据放入b
int a[N],b[N];
int i,size=sizeof(int);
FILE *fp;
if((fp=fopen("words.txt","rb+"))==NULL)
{
printf("不能打开文件!\n");
exit(1);
}
//从键盘输入数据,保存到数组中
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
//将数据写入到文件中
fwrite(a,size,N,fp);
//将文件指针重新定位到文件开头
rewind(fp);
//从文件中读取内容保存到数组b
fread(b,size,N,fp);
for(i=0;i<N;i++)
printf("%d ",b[i]);
fclose(fp);
fp=NULL;
return 0;
}
示例2:
#include<stdio.h>
#define N 2
struct stu{
char name[10];
int num; //学号
int age;
float score;
}boya[N],boyb[N],*pa,*pb;
int main(void)
{
FILE *fp;
int i;
pa=boya;
pb=boyb;
if((fp=fopen("words.txt","wb+"))==NULL)
{
printf("不能打开文件!\n");
exit(1);
}
//从键盘输入数据
printf("输入数据:\n");
for(i=0;i<N;i++,pa++)
{
scanf("%s %d %d %f",pa->name,&pa->num,&pa->age,&pa->score);
}
//将数组baya的数据写入文件
fwrite(boya,sizeof(struct stu),N,fp);
//将文件指针重置到文件开头
rewind(fp);
//从文件读取数据并保存数据至boyb
fread(boyb,sizeof(struct stu),N,fp);
//输出数组boyb中的数据
for(i=0;i<N;i++,pb++)
{
printf("%s %d %d %f\n",pb->name,pb->num,pb->age,pb->score);
}
fclose(fp);
return 0;
}
格式化读写文件
int fscanf ( FILE *fp, char * format, ... );
int fprintf ( FILE *fp, char * format, ... );
成功时返回成功的字符个数。
示例如下;
#include<stdio.h>
#include<stdlib.h>
#define N 2
struct stu
{
char name[10];
int num;
int age;
float score;
}boya[N],boyb[N],*pa,*pb;
int main(void)
{
FILE *fp;
int i;
pa=boya;
pb=boyb;
if((fp=fopen("words.txt","wt+"))==NULL)
{
printf("²»ÄÜ´ò¿ªÎļþ£¡\n");
exit(1);
}
//´Ó¼üÅ̶ÁÈëÊý¾Ý£¬±£´æµ½boyaÖÐ
printf("ÊäÈëÊý¾Ý£º\n");
for(i=0;i<N;i++,pa++)
{
scanf("%s %d %d %f",pa->name,&pa->num,&pa->num,&pa->score);
}
pa=boya;
//½«boyaÖеÄÊý¾ÝдÈëµ½ÎļþÖÐ
for(i=0;i<N;i++,pa++)
{
fprintf(fp,"%s %d %d %f\n",pa->name,pa->num,pa->age,pa->score);
}
rewind(fp);
for(i=0;i<N;i++,pb++)
{
fscanf(fp,"%s %d %d %f\n",pb->name,&pb->num,&pb->age,&pb->score);
}
pb=boyb;
for(i=0;i<N;i++,pb++)
{
printf("%s %d %d %f\n",pb->name,pb->num,pb->age,pb->score);
}
fclose(fp);
return 0;
}
对文件随机进行读写
void rewind ( FILE *fp );
int fseek ( FILE *fp, long offset, int origin );
在fseek()函数中,origin的使用有以下3中方式。(值得说明的是,fseek一般用于二进制文件,如果是文本文件,由于要进行转换
所以计算位置容易出错)
![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPQAAACdCAIAAAAMtsI7AAAL8klEQVR4nO2dy5GrSBBFxye50FawlSGEDOkIuaEl+1m2AzJANjAL8alPZtUFEkhy8iwm3kNQcKlDqkBvin9ubdenvJ/N7dY839kHjnMh/jn7ABxnL1xuxywut2MWl9sxi8vtmAWV+1/H2QcVcn9MYCYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8F5T77/f+8/Nz//37fD6fz+vxE/N4hauNfwsWxcuKjS9lY2f//d7Hg/v7vUcZoyPKMidkhz9sUAq+Ci7vHkG+684RoobZw7u23AFx/NcjXev7efl8DP5XdWHP5oIg2b5fj/u4s6nrxgPK+pk8JOrclAxaexUPMHn3CDKs+suHydu5lNx5NxHyPl75ivffv0Dt1+OHrWJnVe5aDYvi4gWPuZ5H0baWciLvnkGiHP/nyj0aHF3xw0bEiKXaOMRGuavjpdCJasELU74eyVfa5qL9+Xx4uWWDRH/jrgeqlevLnaade3Mu0/c7OdgIh4VQ/aixVe4HW8kev4MTWGWkhqurEi3Ou0eQ8HIkLh62hl9IbtLBoSan0aa86W1I3AlhiaPOztI6vvXpAVn2soXxF09c/dhaOLok5fXn8ynklQwy9fv/oXIn5yH98+P1mUco0+mjzkn8XEWN3CS5EwUWPJHYNuouyy0VJLoujVbuzyxySe7kcv8JbjGnExCXDA3DEjIpox5YuUPBqs+W1gHkFQjy93rNX892K3ck9yBuNr6YTmR4xZfklmOL3PUxaHx7BQ5LwAen6yDz7hHkFcttsXIPJTYZZ8cnMxGYvrqjs/r3ew9GLo9X9PHrcVTlJnozuU6jZz1lkt86jpdbOMjLfOUenHs8+DjxGf75ebw+f7/30pg7eOQ7Oz0ZsfCx2Q5yBwbQIvKP0z6fT9Wg4+TeFMR+5R5LbK3HoqEKeeZSjaNngvPPafO96SG/UIZwdRWpdtH1eHzl3iPItxMej+I2Wcgrya0fM0FAlOd1uSUxEwREeV6XWxIzQUCU53W5JTETBER5XpdbEjNBQJTndbklMRMERHlel1sSM0FAlOd1uSUxEwREeV6XWxIzQUCU53W5JTETBER5XpdbEjNBQJTndbklMRMERHleLXI7zh6okHu/gzgSM0FAlOd1uSUxEwREeV6XWxIzQUCU53W5JTETBER5XpdbEjNBQJTndbklMRMERHlel1sSM0FAlOd1uSUxEwREeV6XWxIzQUCU53W5JTETBER5XpdbEjNBQJTnvYrcXXu7Nc93eYW2S5bEC97P5lYl3EnUQteWD6AUpGuJ9tPDGT/hlicJv6sVDgnfabAmcyZW5wUa2Y+ryN1T+sYfDufx/Wy+q2VyT0yrMH8fF7+7rwpjc+vkjo+7a0OJqQPklkftdO2tcDaW75Taqg6Z9/1swr5Y1KAsOuWGamxS1ebzOfxpm9xzi0OPr5Q76OrKUdSWz+a9n025Ji7faboLDMqe9LI60W6dco/QXTH7OxCMWehv2OQEA3JPVXvaE3+tFIPwxWut3LWivWqn8S5QmLxhE2farVtusi9St4PBZ1SxNg9L+qjBlXKP1xt5jS6X+1kr2it3Guxim9xpEy534SAyp5IF72dza59f32PtiRUXDXViylZUgozfJ9n3B7Vbbvn0pQS6smin8ybb5c5Kj8vNEZ+dbOTbtW2XD1SGVfnKXewA9DrImi8GGWSLJF4+LOla9vrbstNwF2DTvVdugYOYxgbsiRps5QbcaY1aU12Q+8n62QxvBdeOub+X3gJhkJ3Gu0DB5D7tceAV5O6nWsqd+GWVO+vgqtxTKa/0ExZko9zDHxc4A+w02wWEPy3ZfhDfvmwaVq8lchOPyYo9HhbK2g8n9NODYP3wMcam59zl8r18p8QuANgb6OBSOvFnHNVyjwUz+10uFQyWm36MxvR4Ol6NDoHsMzpIOIRPnSNGTtxyajTLX2kLdzo3uVnuaCfn/YLTa5X7/eSrNLUGJndpyB5/UPZm3CT/XPm/tRBHeV6dcl+VM4IQd9GHlUvlHedyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjPq0Vux9kDFXLvdxBHYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvJeRuz4rFDXZPPU/sOeTehBrlSav4ufn4YKcMvl8T8/vwMzbEu6lkrKel5+I81AUy51LOJ8rWvV0enayZ/Ll1IS/1ITfwU6Zxskgp0w+n0/b8342bddDcsdT/xT2QuUNLyiXuzIpD2nWfN7qJTarf21Xmunyu6JY5T5l8vnablG5a9P0lOw5dSK1L6rl7vu5Ro5dzow1QNbO7wXulZH78MnnS2a53DJskRuYRpibfmyeDLXt+vR1OWFpzocit+mbGwGbwviEyedLYi2Ru/aaLZd7n4Mg3vD0JSjxsdzvZ3NrGn6+04oRKyv31HRm+I6Tz2+Um796wby1YzgII3Ijlbtrm+c7uBNM7KYm7V5QtOtBDpx8XqRy1+4me5d7/UFU7+kWVu6xUdqu7PlH4dkjO/N39WweNPl86dZiwbCkeoficu9zEMsrd7JZX3m2J165p1YPmHy+VHXzgXQYPp87vrAfl3ufg1g+5k42izYlarFQ5T5l8vlphWDX80EnTxJjgamfitjduNyrDgJ5YFGWe6IgN7cJu3BqZEnlPmXy+awl/ma2fFtdevIIPuY6y3GtclchKvd0WgMbUqO+mxWH803bgi/1y3pN+b+1EEd53svKrZIzgvjk8ywutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvFrkdpw9UCH3fgdxJGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvC63JGaCgCjP63JLYiYIiPK8LrckZoKAKM/rcktiJgiI8rwutyRmgoAoz+tyS2ImCIjyvFeRuzbfKDEHDDu7yERpesvqZG5U21yQ49+sUGok2yqdQg3+X+mBvGfOy3MVufvKFEbENCab5ea35ibsIYOc8maFUiOZc6X5AYsT3XN54TmQ90Wn3OgE2WFByt7ykemJvYQhnI4PWK8c5NQ3K3CNNE0yFVtt8ku2rNTtWTvbvwg65R6huygruEF94Jzk3m2we+U+580KlUaI2QKLM7tyimJynzYy0S03eW5SJYPBZ9QJ+wxLhqtnwVyBJ7xZAZwHGZ+2mLG7as+phVu73PTgIlzwfja39vm1NJaVmbkVHGx07TjTO/AVUAty9JsVyo18tw++APaSG5i+flfUy53UoGyW1q5tO7oE1yr3t3g1LV1Y8msIqEDFIAe+WQG7K530rsvNjLqrec+r2n1/BbmD883e2AzqlW4C86dfzbN7NsN/si54Dx+h7UFBDnuzAvjIZdR7hzE3dGOwN1eQu5++ZbmztaxyT305bkb0XbqxQOUe2znizQqg3MPF1rZNSW5+dMHkPXs4MnIJub992TRsxYTljh8ThJvF9XAs7Pw3AXmp0U9LznizAij3PDjn5C5eR+wN9LnDkRHVcqcnPliUvZypLnd+0rPNRvfoN+RkUmT20EHOeLMC2kifXidbf6E8c7rwFJ1yD2e4cP3Ha6y6oeTHGuSWWa+teTRmDOV5dcp9Vc4I4m9WYHG5JTETBER5XpdbEjNBQJTndbklMRMERHlel1sSM0FAlOd1uSUxEwREeV6XWxIzQUCU53W5JTETBER5XpdbEjNBQJTn1SK34+zB+XI7zuVwuR2zuNyOWVxuxywut2MWl9sxi8vtmMXldszicjtmcbkds7jcjllcbscs/wEkWH4ovTZjDQAAAABJRU5ErkJggg==)
获取文件的大小
1.可以通过打开文件,然后利用fseek()跳转到文件尾,然后通过ftell()函数来获取文件的大小。
缺点是ftell()函数的返回值是long,如果是4个字节的大小的话,文件的大小不超过2个G还可以应付,太大时就不行了。
2.超大文件还可以通过fsetpos和fgetpos获取文件大小
缺点是,它需要加载文件到内存中,当文件太多时,会比较耗时。
3.直接读取文件信息获取文件大小,在linux下可以使用如下:
- #include <sys/stat.h>
- int file_size2(char* filename)
- {
- struct stat statbuf;
- stat(filename,&statbuf);
- int size=statbuf.st_size;
- return size;
- }