c标准IO
标准IO和文件的相关操作,基本上都是以f开头的一系列函数。
标题 | 操作对象 | IO缓冲区 | 手册位置 |
---|---|---|---|
系统IO | 文件描述符,数组下标 | 不带IO缓冲区 | 调用系统库函数接口,基本来自于man 2手册 |
标准IO | 文件流指针,文件指针 | 携带IO缓冲区 | 调用系统库函数接口,基本来自于man 3手册 |
系统IO在打开文件之后,会得到文件的描述符,文件操作基本围绕着文件描述符进行。
标准IO在打开文件之后,会得到文件流的指针,文件操作基本围绕着文件流指针进行。
fopen文件打开
#include <stdio.h>
函数原型:
//通过文件路径打开文件
FILE * fopen(const char *path,const char *mode);
//通过文件描述符打开文件
FILE * fdopen(int fd,const char *mode);
函数参数:
const char *path:需要打开的文件路径名
int fd:需要打开的文件的文件描述符
const char *mode:打开文件的权限
返回值:
成功:返回值一个文件流指针
失败:返回NULL
//以路径的形式打开文件FILE *fp = fopen("test.txt", "r");if (fp == NULL){perror("fopen");return -1;}printf("打开文件之后的指针地址:%p\n",fp );
在调用fopen时,文件的打开方式是必须的,最基本的文件打开方式有以下几种:
打开方式 | 说明 |
---|---|
r | 以只读的方式打开文件。只允许读取,不允许写入,文件必须存在,否则打开失败 |
w | 以写入的方式打开文件,如果文件不存在,那么创建一个新的文件如果文件存在,那么清空文件内容(相当于删除源文件,创建一个新文件) |
a | 以追加的方式打开文件,如果文件不存在,那么创建一个新文件如果文件存在,那么将写入的数据追加到文件末尾(文件原有内容会保留) |
r+ | 以读写的方式打开文件,及可以读取也可以写入,文件必须存在,否则打开失败 |
w+ | 以写入/更新的方式打开文件,相当于w和r+的叠加效果,既可以读取也可以写入,如果文件不存在,那么创建一个新的文件,如果文件存在,就清空文件内容 |
a+ | 以追加/更新的方式打开文件,相当于a和r+的叠加效果,既可以读取也可以写入,如果文件不存在,那么久创建一个新文件如果文件存在,那么就将写入的数据追加到文件末尾 |
t | 文本文件,如果不写默认为 t |
b | 二进制文件 |
读写权限和读写方式可以组合使用,但是必须将读写方式放在读取权限的中间或者末尾
1.将读写方式放到读写权限的末尾:rb、wt、r+b、a+t
2.将读写方式放在读写权限的中间:rb+、wt+、ab+
整体来说,文件打开方式由:r、w、a、t、b、+六个字符拼成,各个字符的含义:
- r读
- w写
- a追加
- t文本文件
- b二进制文件
- +读和写
文件的关闭fclose()
#include <stdio.h>
函数原型:
int fclose(FILE * stream);//函数参数为fopen返回的文件指针
返回值:
成功:返回0
失败:返回EOF,EOF实际上是-1
在stdio.h头文件中查看EOF的值
cat /usr/include/stdio.h
int ret=fclose(fp);if(ret==EOF){perror("文件关闭失败!");return -1;}
文件数据块读写
#include <stdio.h>
数据块读取的函数原型:
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);函数参数:
ptr:数据存储需要的缓冲区位置
size:每块存储区拥有多少个字节
nmemb:需要多少块这样的存储区
stream:文件流指针对象函数的返回值:
成功:返回读取或者写入的有效数据块的个数
失败:返回0或者其他小于0的数据
#include <stdio.h>
#include <string.h>int main(int argc, char const *argv[])
{//以可读可写的方式打开文件FILE *fp=fopen(argv[1],"r+");if(fp==NULL){perror("文件打开失败!");return -1;}//读取数据char buf[100];//存储读取的数据//读取数据,每个空间2个字节,读取4块这样的内存int ret=fread(buf,2,4,fp);//读取数据,每个空间10个字节,读取10块这样的内存//int ret=fread(buf,10,10,fp);printf("buf:%s ret:%d\n",buf,ret );//关闭ret=fclose(fp);if(ret==EOF){perror("文件关闭失败!");return -1;}return 0;
}
判断文件操作feof和ferror
int feof(FILE * stream);
返回值:
成功:返回非0值,找到了文件的末尾
失败:返回0值,说明文件没有到达末尾//判断操作过程中是否出现错误
int ferror(FILE * stream);
返回值:
成功:返回非0值,存在操作错误
失败:返回0值,说明没有错误
#include <stdio.h>
#include <string.h>int main(int argc, char const *argv[])
{FILE *fp1=fopen(argv[1],"r+");FILE *fp2=fopen(argv[2],"r+");if(fp1==NULL||fp2==NULL){perror("文件打开失败!");return -1;}char buf[100];//存放读取内容int ret,rat;while(1){//每次读取之前,先清理一下缓冲区(数组)memset(buf,0,100);//保证buf中没有上次读取出来的残留数据fread(buf,1,1,fp1);//每次读取1个字节//判断文件是否到达末尾ret=feof(fp1);//判断读取的时候是否出错rat=ferror(fp1);printf("eof:%d error:%d\n",ret,rat );//如果读取到了文件的末尾,结束循环if(ret!=0){break;}//写入数据fwrite(buf,1,1,fp2);}ret=fclose(fp1);if(ret==EOF){perror("文件关闭失败!");return -1;}ret=fclose(fp2);if(ret==EOF){perror("文件关闭失败!");return -1;}return 0;
}
数据字节和行处理-输入相关
#include <stdio.h>
int fgetc(FILE * stream);//输入单个字节到stream流中char * fgets(char * s,int size,FILE * stream);
//输入字符串到stream流中int getc(FILE * stream);//输入单个字符到stream流中函数返回值:
fgetc() getc()
成功:获取字符或无符号字符
失败:返回EOF或者读取到文件末尾fgets()
成功:返回读到的字符串指针
失败:返回NULL
数据字节和行处理-输出相关
#include <stdio.h>
int fputc(int c,FILE * stream);//输出一个字符c到stream流int fputs(const char * s,FILE * stream);
//输出一个字符串到stream流中int putc(int c,FILE * stream);//输出一个字符串c到stream流函数参数:
int c:单个操作字符
const char * s:字符串对象s
FILE * stream:文件指针返回值:
fputc() fputs()
成功:返回写入的字符或者无符号字符
失败:返回EOFfputs()
成功:返回操作的字符串个数
失败:返回EOF
文件偏移fseek
#include <stdio.h>//按照自身需求定位不同的位置
int fseek(FILE * stream,long offset,int whence);//函数调用成功返回当前位置
long ftell(FILE * stream);//将偏移设置到文件的开头 fseek(stream,0,SEEK_SET)
void rewind(FILE * stream);函数参数:
FILE * stream:需要操作的文件流指针
long offset:需要偏移的长度,单位字节
int whence:偏移的起始位置SEEK_SET文件的开头SEEK_CUR文件当前的位置SEEK_END文件的末尾返回值:
fseek()成功:返回0 失败:返回-1
ftell()成功:返回当前偏移的位置
rewind()无返回值数据
#include <stdio.h>int main(int argc, char const *argv[])
{FILE * fp=fopen(argv[1],"r+");if(fp==NULL){perror("文件打开失败!");return -1;}fwrite("helloworld",10,1,fp);//将光标定位到文件开头//rewind(fp);//fseek(fp,0,SEEK_SET);//光标定位到文件的开头//fseek(fp,0,SEEK_END);//光标定位到文件的末尾//fseek(fp,-5,SEEK_END);//光标定位在离文件末尾向前偏移5个字节fseek(fp,5,SEEK_SET);//光标定位在离文件开头向后偏移5个字节char buf[20]={0};fread(buf,10,2,fp);printf("buf:%s\n",buf );long size=ftell(fp);printf("size:%ld\n",size );//关闭int ret=fclose(fp);if(ret==EOF){perror("文件关闭失败!");return -1;}return 0;
}
字符串格式化处理fprintf /fscanf
sprintf()按照一定的格式拼接数据保存到对应的字符串中
int sprintf(char *str,const char * format,...);
函数参数:
char *str:字符串地址
const char * format:字符串操作格式
...:变参数据,变参的内容由格式化内容决定按照一定的格式拼接数据保存到stream对应的文件流中
int fprintf(FILE * stream,const char * format,...);
函数参数:
FILE * stream:需要用来保存数据的文件流指针
const char * format:字符串操作格式
...:变参数据,变参的内容由格式化内容决定
sscanf按照一定的格式从字符串拆分数据保存到变量空间
int sscanf(const char *str,const char * format,...);fscanf按照一定的格式从文件中拆分数据保存到变量空间
int fscanf(FILE * stream,const char * format,...);
#include <stdlib.h>struct student
{char name[10];int age;float high;
};int main()
{char * str="姓名:jack 年龄:19 身高:180.50";struct student stu;sscanf(str,"姓名:%s 年龄:%d 身高:%f",stu.name,&stu.age,&stu.high);printf("%s %d %.2f\n",stu.name,stu.age,stu.high );FILE * fp=fopen("6.txt","r+");if(fp==NULL){perror("文件打开失败!");return -1;}struct student stu1;fscanf(fp,"姓名:%s 年龄:%d 身高:%f",stu1.name,&stu1.age,&stu1.high);printf("%s %d %.2f\n",stu1.name,stu1.age,stu1.high );int ret=fclose(fp);if(ret==EOF){perror("文件关闭失败!");return -1;}return 0;
}