ASCII文件和二进制文件的比较:
ASCII文件便于对字符进行逐个处理,也便于输出字符。但一般占存储空间较多,而且要花费转换时间。
二进制文件可以节省外存空间和转换时间,但一个字节并不对应一个字符,不能直接输出字符形式。一般中间结果数据需要暂时保存在外存上,以后又需要输入内存的,常用二进制文件保存。
|
C语言对文件的处理方法:
缓冲文件系统:系统自动地在内存区为每一个正在使用的文件开辟一个缓冲区。用缓冲文件系统
进行的输入输出又称为高级磁盘输入输出。
非缓冲文件系统:系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。用非缓
冲文件系统进行的输入输出又称为低级输入输出系统。
|
r 打开一个文本文件,读取
w 创建一个文本文件,写入(已经有的覆盖)
a 打开一个文本文件,光标定位到末尾写入
r+ 打开一个文本文件,读取,写入(先读,独到末尾可以写新数据不会覆盖)
w+ 创建一个文本文件,读取,写入(会覆盖)
a+ 打开一个文本文件,光标定位到末尾,读取、写入
"rb+" 打开一个用于读/写的二进制文件
"wb+" 创建一个用于读/写的二进制文件
"ab+" 打开一个用于读/写的二进制文件
|
“r” (只读)为输入打开一个文本文件
“w” (只写)为输出打开一个文本文件,也会创建一个文件
“a” (追加)向文本文件尾增加数据
“rb” (只读)为输入打开一个二进制文件
“wb” (只写)为输出打开一个二进制文件
"ab“ (追加)向二进制文件尾增加数据
"r+“ (读写)为读/写打开一个文本文件
"w+” (读写)为读/写建立一个新的文本文件
"a+” (读写)为读/写打开一个文本文件
"rb+“ (读写)为读/写打开一个二进制文件
“wb+“ (读写)为读/写建立一个新的二进制文件
“ab+” (读写)为读/写打开一个二进制文件
|
常见的读取字符操作:
从一个文本文件顺序读入字符并在屏幕上显示出来:
ch = fgetc(fp);
while(ch != EOF)
{
putchar(ch);
ch = fgetc(fp);
}
注意:EOF不是可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为 -1是合适的。当读入的字符值等于-1时,表示读入的已不是正常的字符而是文件结束符。
|
从一个二进制文件顺序读入字符:
while(!feof(fp))
{
ch = fgetc(fp);
}
注意:ANSI C提供一个 feof()函数来判断文件是否真的结束。如果是文件结束,函数feof(fp)的值为1(真);否则为0(假)。以上也适用于文本文件的读取。
|
|
fread (buffer,size,count,fp);
fwrite(buffer,size,count,fp);
参数说明:
buffer:是一个指针。
对fread 来说,它是读入数据的存放地址。
对fwrite来说,是要输出数据的地址(均指起始地址)。
size: 要读写的字节数。
count: 要进行读写多少个size字节的数据项。
fp: 文件型指针。
perror()系统调用 fp=fopen(argv[1],"r");
if( NULL==fp )
{
perror("fopen"); //No such file or directory
}
perror("写要输出的内容"); 输出错误信息
|
//两个函数读到文件尾返回 0;fwrite 写数据的时候count一般要写buffer中数据的长度strlen(str),不然会写进去一些不是自己想要的内容 int i=0 ; int ret=0 ; FILE* fp ; fp=fopen(……)
int ret ;
ret=fread(&i,sizeof(int),1,fp); //从fp所指的文件中读一个大小为int的数放到变量i里面
char a[100]; memset(a,0,sizeof(a));
ret=fread(a,sizeof(char),sizeof(a),fp); //从fp所指的文件中读数组a大小的一些数据放到数组a中
用于二进制文件:
char a[100]; strcpy(a,”hello”);
ret=fwrite(a,sizeof(char),strlen(a),fp)
//这两个函数都是写二进制
|
格式化读写函数(fprintf()和fscanf())
函数调用:
fprintf ( 文件指针,格式字符串,输出表列);
fscanf ( 文件指针,格式字符串,输入表列);
例:
fprintf(fp,”%d,%6.2f”,i,t);
fscanf (fp,”%d,%f”,&i,&t);
|
注意:
用 fprintf 和 fscanf 函数对磁盘文件读写,使用方便,容易理解,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintf和fscanf函数,而用fread和fwrite函数。
|
|
其他读写函数( putw() 和 getw() )
函数调用:
putw(int i,FILE * fp);
int i = getw(FILE * fp);
|
函数功能:
对磁盘文件中读写一个字(整数)。
例:
putw(10,fp);
i = getw(fp);
|
|
fgets函数
函数作用:
从指定文件读入一个字符串。
函数调用:
fgets(str,n,fp);
从fp指向的文件输入n-1个字符,在最后加一个’\0’。
返回值:
str的首地址。
|
fputs函数(不会读入换行)
函数作用:
向指定的文件输出一个字符串。
函数调用:
fputs(“china”,fp);
第一个参数可以是字符串常量、字符数组名或字符型
指针。字符串末尾的′\0′不输出。
返回值:
输入成功,返回值为0;
输入失败,返回EOF。
|
|
文件的定位:
顺序读写和随机读写
顺序读写:
位置指针按字节位置顺序移动。
随机读写:
读写完上一个字符(字节)后,并不一定要读写其
后续的字符(字节),而可以读些文件中任意位置
上所需要的字符(字节)。
|
fseek函数(一般用于二进制文件)
函数功能:
改变文件的位置指针。
函数调用形式:
fseek(文件类型指针,位移量,起始点)
起始点: 文件开头 SEEK_SET 0
文件当前位置 SEEK_CUR 1
文件末尾 SEEK_END 2
位移量:以起始点为基点,向前移动的字节数。一般要求为long型。
|
|
ftell函数
函数作用:
得到流式文件中的当前位置,用相对于文件开头的位移量来表示。
返回值:
返回当前位置,出错时返回-1L(-1)。
应用举例:
i = ftell(fp);
if(i==-1L) printf(“error\n”);
|
出错的检测
ferror函数
调用形式:
ferror(fp);
返回值:
返回0,表示未出错;返回非0,表示出错。
在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。
|
|
clearerr函数
调用形式:
clearerr(fp);
函数作用:
使文件错误标志和文件结束标志置为0。
只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何其他一个输入输出函数。
文本模式,写入 \n ,实际写入的是 \r\n
读取的时候,\r\n 会被读为 \n
|
打开文件 fopen() 打开文件
关闭文件 fclose() 关闭文件
文件定位 fseek() 改变文件位置指针的位置
rewind() 使文件位置指针重新至于文件开头
ftell() 返回文件位置指针的当前值
文件状态 feof() 若到文件末尾,函数值为真
ferror() 若对文件操作出错,函数值为真
clearerr() 使ferror和feof()函数值置零
文件读写 fgetc(),getc() 从指定文件取得一个字符
fputc(),putc() 把字符输出到指定文件
fgets() 从指定文件读取字符串
fputs() 把字符串输出到指定文件
getw() 从指定文件读取一个字(int型)
putw() 把一个字输出到指定文件
fread() 从指定文件中读取数据项(二进制文件)
fwrite() 把数据项写到指定文件中(二进制文件)
fscanf() 从指定文件按格式输入数据
fprintf() 按指定格式将数据写到指定文件中
sscanf() 从buffer缓冲区读取数据,按规定格式放到变量中
sprintf() 把输出发送到buffer缓冲区
这些函数用的时候要注意memset初始化,和fseek偏移文件指针
|
int fseek( FILE *stream, long offset, int origin ); //参数表1、文件指针 2、位移量,3、当前光标位置
fgetc()函数返回来自stream(流)中的下一个字符,如果到达文件尾或者发生错误时返回EOF.
(origin可设置值) | 说明 |
SEEK_SET | 从文件的开始处开始搜索 |
SEEK_CUR | 从当前位置开始搜索 |
SEEK_END | 从文件的结束处开始搜索 |
char fgetc( FILE *stream ); //从文件流中获取一个字符,获取失败返回EOF(-1);
int fscanf( FILE *stream, const char *format, ... ); //返回已赋值的变量的个数,未进行任何分配时返回EOF( -1 )。
l
int fprintf( FILE *stream, const char *format, ... ); //返回已读入的变量的个数,未进行任何分配时返回EOF( -1 )。
l
l fprint(fp,”hello”);和printf工作一样,不过fprint是在文件里输入
fseek()成功时返回0,失败时返回非零. 你可以使用fseek()移动超过一个文件,但是不能在开始处之前. 使用fseek()清除关联到流的EOF标记.
char * fgets( char *str, int num, FILE *stream ); //
//这个函数每次读之前都会自己清空str里的内容,所以不用自己认为的在循环第二次读之前使用memset
用于文本文档 int a[100], fgets(a,sizeof(a),fp)
char a[1024];
微软编码 GB2132 汉字表示2个字节
网页 UTF—8 汉字3个字节
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char buf[100]="";
FILE *fp = fopen("1.txt","r");
while( memset(buf,0,sizeof(buf)),fgets(buf,sizeof(buf),fp) != NULL )
{
printf("%s",buf);
}
system("pause");
}
|
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
int num;
char name[20];
char sex;
float score;
}stu;
1.txt 1001 liming 85.3 M
1001 liming 85.3 M
1001 liming 90.3 M
sscanf fscanf scanf 这些函数读入格式不能像 %4d,%4.2f 但是所有 printf 的函数都可以加这些格式
|
#include"1.h"
int main()
{
FILE *fp;
char buf[128]="";
stu s1;
int ret;
fp = fopen("1.txt","r+");
if(NULL == fp)
{
perror("fopen");
}
memset(buf,0,sizeof(buf));
fgets(buf,sizeof(buf),fp);
ret = sscanf(buf,"%d%s%f %c",&s1.num,&s1.name,&s1.score,&s1.sex);
//前面读入格式有一个空格,表示读的时候要空一个然后再把后面的字符读入到s1.sex;这里要是没有空格,文件里M就要紧跟成绩
printf("%d",ret);
memset(buf,0,sizeof(buf));
s1.score += 5;
ret = sprintf(buf,"%s%d %s %3.1f %c","\n",s1.num,s1.name,s1.score,s1.sex);
//写入的时候要先写一个空格,然后写入s1.sex;%3.1f表示写入数字占3个字节宽度,小数点后有一位小数。小数点也占用一个宽度,但是如果数据比3长(小数点前的数据多余1)就全部显示,但是小数点后多余1位的会被舍弃;
fputs(buf,fp);
fclose(fp);
system("pause");
}
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int num;
char name[20];
char sex;
float score;
}stu;
|
#include"1.h"
int main()
{
FILE *fp;
char buf[128]="";
stu s1;
int ret;
fp = fopen("1.txt","rb+");
if(NULL == fp)
{
perror("fopen");
}
s1.num = 1000;
strcpy(s1.name,"LiMing");
s1.sex = 'M';
s1.score = 90.5;
fwrite(&s1,sizeof(s1),1,fp);
fread(&s1,sizeof(s1),1,fp);
printf("%d %s %3.1f %c",s1.num,s1.name,s1.score,s1.sex);
fclose(fp);
system("pause");
}
|
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp = fopen("1.txt","r");
char buf[1024]="";
char word[30]="";
int ret=0,index=0;
int i=0;
fseek(fp,0,SEEK_SET);
while( memset(buf,'\0',sizeof(buf) ), ( ret = fread(buf,sizeof(char),sizeof(buf)-1,fp) ) != 0)
{
strlwr(buf);
for(i=0;i<ret;i++)
{
index = 0;
while(buf[i]>='a'&&buf[i]<='z')
{
word[index++]=buf[i++];
}
if(index != 0)
{
word[index] = '\0';
printf("%s\n",word);
}
}
}
fclose(fp);
system("pause");
}
|
fread读文件时文件指针会自动偏移的,读数组个一定要是sizeof(buf)-1个,因为字符串数组有一个‘\0’。memset初始化一般为‘\0’,‘0’; 这段代码本来是要想提高统计文件词频的效率,但是这个有一个bug,这个每次读一个buf数组,有可能一个单词只读了一半;一行一行的读也不行,有的单词可能在一行的最后没写完又接到第二行写。 |