有一点感觉很重要,那就是用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) 双字节作为文本文件换行符,而Unix文本文件的换行符只有一个字节LF(0x0A) 。在C语言中,也是以LF即' '为换行符。
在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("文件出错!
");
else
printf("文件成功!
");
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())!='
') //这里发现可以录入汉字“你好”到fp所指的文件中
{
putc(ch,fp);
}
return 0;
}
然后把上面的程序改为
fopen("words.txt","r");
while((ch=getc(fp))!=EOF)
{
putc(ch); //这里发现,是可以输出文件中的中文的
}
以字符串的方式读取文件
在c语言中没有按行读取文件的函数,可以把fgets()中的参数n设置的足够大,以至于可以读取一行的数据来代替读取一行的数据。
fgets()函数遇到换行会将换行读取到字符串中,然后在字符串末尾添加 ;而gets()函数会忽略换行。
char *fgets(char *str,int n,FILE *fp); //读取成功返回字符串的首地址,即str,否则返回NULL。读取到的字符串末尾自动添加 ,也 就是说实际读取到的是n-1个字符。遇到 则自动结束。
示例:
#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("不能打开文件!
");
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("不能打开文件!
");
exit(1);
}
//从键盘输入数据
printf("输入数据:
");
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
",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("²»ÄÜ´ò¿ªÎļþ£¡
");
exit(1);
}
//´Ó¼üÅ̶ÁÈëÊý¾Ý£¬±£´æµ½boyaÖÐ
printf("ÊäÈëÊý¾Ý£º
");
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
",pa->name,pa->num,pa->age,pa->score);
}
rewind(fp);
for(i=0;i<N;i++,pb++)
{
fscanf(fp,"%s %d %d %f
",pb->name,&pb->num,&pb->age,&pb->score);
}
pb=boyb;
for(i=0;i<N;i++,pb++)
{
printf("%s %d %d %f
",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一般用于二进制文件,如果是文本文件,由于要进行转换
所以计算位置容易出错)
获取文件的大小
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;
- }