概念:一组相关数据的有序集合
文件有文件名和路径
Linux支持不同的文件类型:
注意:操作系统不同,所支持的文件类型也不同
标准I/O由ANSI C标准定义
主流操作系统上都实现了C库
作用:标准I/O通过缓冲机制减少系统调用,实现更高的效率,移植性好
解释:标准I/O函数在执行时用到系统调用,Linux必须从用户态切换到内核态,处理相应的请求,然后再返回到用户态。如果频繁的执行系统调用会增加系统的开销。为了避免这种情况,标准I/O使用时再用户空间创建缓冲区,读写时先操作缓冲区,在合适的时机再通过系统调用访问实际的文件,从而减少了使用系统调用的次数。
FILE
流(stream)
FILE又被称为流
文本流/二进制流
不同操作系统对流的定义不同:
Windows
Linux
标准I/O-流的缓冲类型
标准I/O概述http://www.proedu.com.cn:8800/web/shareVideo/index.action?id=1012531&ajax=1
标准I/O预定义3个流,程序运行时自动打开
标准输入流 | 0 | STDIN_FILENO | stdin |
标准输出流 | 1 | STDOUT_FILENO | stdout |
标准错误流 | 2 | STDERR_FILENO | stderr |
FILE *fopen(const char *path,const char *mode);
成功返回流指针,失败时返回NULL。
fopen示例:
#include
int main(int argc,char *argv[])
{
FILE *fp;
if((fp=fopen("test.txt","r+")==NULL){
printf("fopen error\n");
return -1;
}
...
return 0;
}
流的打开与关闭http://www.proedu.com.cn:8800/web/shareVideo/index.action?id=1012532&ajax=1
extern int errno;
void perror(const char *s);
char *strerror(int errno);
#include
int main(int argc,char *argv[])
{
FILE *fp;
if((fp=fopen("test.txt",r+)==NULL)
{
perror("fopen");
return -1;
}
...
fopen:No such file or directory
#include
#include
#include
int main(int argc,char *argv[])
{
FILE *fp;
if((fp=fopen("test.txt",r+)==NULL)
{
printf("fopen:%s\n",strerror(errno));
return -1;
}
...
fopen:No such file or directory
错误处理http://www.proedu.com.cn:8800/web/shareVideo/index.action?id=1012533&ajax=1
int fclose(FILE *stream);
程序中能够打开的文件或流的个数有限制,如何测试?
思路:循环打开流,成功则计数器加一,直到出错为止。
答案:1021+stdin+stdout+stderr=1024
/*************************************************************************
> File Name: filebyte.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月22日 星期六 20时1分29秒
************************************************************************/
#include
int main(int argc, const char *argv[])
{
int num=0;
FILE *fp;
while(1)
{
if((fp=fopen("1.txt","a+"))!=NULL)
{
num++;
}
else
{
perror("fopen");
break;
}
}
printf("The IO stream max is %d\n",num);
fclose(fp);
return 0;
}
int getc(FILE *stream);
int fgetc(FILE *stream);
int getchar(void);
成功返回读取的字符,若到文件结尾或出错时返回EOF
getchar()等同于fgetc(stdin).
int ch;
ch=fgetc(stdin);
printf("%c\n",ch);
/*************************************************************************
> File Name: filebyte.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月22日 星期六 20时19分22秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
int ch, count=0;
if((fp=fopen(argv[1],"r"))==NULL)
{
perror("fopen");
return -1;
}
while((ch=fgetc(fp))!=EOF)
{
count++;
}
printf("total %d bytes\n",count);
return 0;
}
int putc(int c,FILE * stream);
int fputc(int c,FILE * stream);
int putchar(int c);
成功返回写入的字符;出错返回EOF;
putchar(c)等同于fputc(c,stdout);
/*************************************************************************
> File Name: a_zfile.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月22日 星期六 20时37分28秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
int ch;
FILE *fp;
if((fp=fopen(argv[1],"w"))==NULL)
{
perror("fopen");
return -1;
}
for(ch='a';ch<='z';ch++)
{
fputc(ch,fp);
}
return 0;
}
/*************************************************************************
> File Name: mycp.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月22日 星期六 21时30分20秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
int ch;
FILE *fps,*fpd;
if(argc<3)
{
printf("%s srcfile desfile\n",argv[0]);
}
if((fps=fopen(argv[1],"r"))==NULL)
{
perror("fopen src");
return -1;
}
if((fpd=fopen(argv[2],"w"))==NULL)
{
perror("fopen des");
return -1;
}
while((ch=fgetc(fps))!=EOF)
{
fputc(ch,fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
流的读写http://www.proedu.com.cn:8800/web/shareVideo/index.action?id=1012534&ajax=1
char * gets(char *s);//不建议使用,容易造成缓冲区溢出
char * fgets(char * s,int size,FILE * stream);
成功返回s,失败或到达文件末尾:NULL。
fgets遇到‘\n'或已输入size-1个字符时返回,总是包含'\0',不能保证每次都能读出一行。
#define N 6
char buf[N];
fgets(buf,N,stdin);
printf("%s",buf);
假设键盘输入分别是:abcd<回车> abcdef<回车>,buf中的内容是?
int puts(const char *s);
int fputs(const char *s,FILE *stream);
成功返回s,失败:NULL
puts将缓冲区s的字符串输出到stdout,并追加'\n'
puts("hello world");
FILE *fp;
char buf[]="hello world";
if((fp=fopen(argv[1],"a"))==NULL)
{
perror("fopen");
return -1;
}
fputs(buf,fp);
注意:输出的字符串中可以包含'\n',也可以不包含
如何统计一个文本文件包含多少行?
1.fgetc? 效率低
/*************************************************************************
> File Name: fgtcline.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 11时11分45秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
int ch,num=0;
if(argc<2)
{
printf("usage : %s \n",argv[0]);
return -1;
}
if((fp=fopen(argv[1],"r"))==NULL)
{
perror("fopen");
return -1;
}
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n')//疑问:此处换成if(fgetc(fp)=='\n'),测试结果不对
{
num++;
}
}
printf("the line of %s is %d\n",argv[1],num);
return 0;
}
因为fgetc(fp)在一次循环中执行了2次。
2.fgets?如何判断读取了一行?
buf[strlen[buf]-1]?='\n'
/*************************************************************************
> File Name: fileline.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 10时50分57秒
************************************************************************/
#include
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
char buf[128];
int num=0;
if(argc<2)
{
printf("Usage : %s \n",argv[0]);
return -1;
}
if((fp=fopen(argv[1],"r"))==NULL)
{
perror("fopen");
return -1;
}
while(fgets(buf,128,fp)!=NULL)
{
if(buf[strlen(buf)-1]=='\n')
num++;
}
printf("the line of %s is %d\n",argv[1],num);
return 0;
}
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
size:读取的每个记录的大小;nmemb:读取的记录数
成功返回实际读取到的nmemb数目,失败返回EOF
既可以读写文本文件,也可以读写数据文件。
int s[10];
if(fread(s,sizeof(int),10,fp)<0)
{
perror("fread");
return -1;
}
struct student
{
int no;
char name[8];
float score;
}s[]={
{1,"zhang",97},{2,"wang",99}};
fwrite(s,sizeof(student),2,fp);
如何利用fread、fwrite实现文件的复制?
/*************************************************************************
> File Name: freadwritecp.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 13时43分39秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fps,*fpd;
char ch[128];
int n;
if(argc<3)
{
printf("Usage : %s \n",argv[0]);
return -1;
}
if((fps=fopen(argv[1],"r"))==NULL)
{
perror("fopen src:");
return -1;
}
if((fpd=fopen(argv[2],"w"))==NULL)
{
perror("fopen des:");
return -1;
}
while((n=fread(ch,1,128,fps))>0)
{
fwrite(ch,1,n,fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
什么情况会刷新流?
int fflush(FILE *fp);
成功:0,失败:EOF
Linux下只能刷新输出缓冲区
/*************************************************************************
> File Name: fflush.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 15时00分01秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
if((fp=fopen("tetx.txt","w"))==NULL)
{
perror("fopen:");
return -1;
}
fputc('a',fp);
fflush(fp);
while(1);
return 0;
}
#include
long tell(FILE *stream);
int fseek(FILE *stream,long offset,int whence);
void rewind(FILE *stream);
ftell成功返回流的当前读写位置,出错返回EOF
fseek()定位一个流,成功返回0,失败返回EOF
whence基准值,参数:SEEK_SET/SEEK_CUR/SEEK_END
offset参数:偏移量,可正可负
rewind()将流定位到文件的开始位置
读写流时,当前读写位置自动后移
在文件末尾追加字符't'
FILE *fp=fopen("text.txt","r+");
fseek(fp,0,SEEK_END);
fputc('t',fp);
获取文件长度
/*************************************************************************
> File Name: filelongfseek.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 15时27分59秒
************************************************************************/
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
if((fp=fopen("text.txt","r+"))==NULL)
{
perror("fopen");
return -1;
}
fseek(fp,0,SEEK_END);
printf("length of file is %ld\n",ftell(fp));
return 0;
}
include
int ferror(FILE *stream);
int feof(FILE *stream);
ferror()返回1表示流出错;否则返回0
feof()返回1表示文件已到末尾;否则返回0
标准I/O-格式化输出
#include
int printf(const char *fmt,...);
int fprintf(FILE *stream,const char *fmt,...);
int sprintf(char *buf,const char *fmt,...);
成功:输出字符数(sprintf返回存入数组中的字符数)
失败:EOF
以指定格式“年-月-日”分别写入文件和缓冲区
int year,month,date;
FILE *fp;
char buf[64];
year=2014;month=10;date=26;
fp=fopen("text.txt","a+");
fprintf(fp,"%d-%d-%d\n",year,month,date);
sprintf(buf,"%d-%d-%d\n",year,month,date);
/*************************************************************************
> File Name: time.c
> Author: 徐维龙
> Mail: [email protected]
> Created Time: 2020年02月23日 星期日 16时18分08秒
************************************************************************/
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
FILE *fp;
char buf[64];
int line =0;
time_t t;
struct tm *tp;
if((fp=fopen("time.txt","a+"))==NULL)
{
perror("fopne");
return -1;
}
while(fgets(buf,64,fp)!=NULL)
{
if(buf[strlen(buf)-1]=='\n');
line++;
}
while(1)
{
time(&t);
tp=localtime(&t);
fprintf(fp,"%02d、%04d-%02d-%02d %02d:%02d:%02d\n",++line,tp->tm_year+1970,\
tp->tm_mon+1,tp->tm_mday,tp->tm_hour, tp->tm_min,tp->tm_sec);
fflush(fp);
sleep(1);
}
fclose(fp);
return 0;
}