在C语言体系中,文件操作对于初学者一直是个神奇的存在,为什么呢?因为文件为什么能通过指针来操作一直是个迷。
而且初学者第一次接触了FILE* 这个系统定义的指针类型,可容易因为陌生感而产生畏难情绪,很可惜,本文假定读者已经走过了
对一些系统定义的畏难阶段,不算老手,但是也不完全是 菜鸟。现在,我们一起来操作文件
常用函数一(api)
- fopen
- fread
- fwrite
- fclose
基础读写
如果你打开过window系统的 .txt文档,在里面写过情书,那么你应该完全会对此编程。
下面,我们来编码向,poem.txt中写一段情话。一般的,你会把情书放在E盘的根目录下,当然,这里是假设,因为我是这么干的,然后就可以开始读取本情书了:
#include<stdio.h> #include<stdlib.h> int main() { //定义文件的名称变量 char*filename_or_path ="E:\poem.txt"; //以写入的方式 打开文件 FILE *file_point_write = fopen(filename_or_path,"w"); char*poem_duc ="Do you want to date with me?"; //写入情书内容 int writeLenght = fwrite(poem_duc,sizeof(char), strlen(poem_duc),file_point_write); //关闭本文件 fflush(file_point_write); fclose(file_point_write); //以读取的方式 打开本文件 FILE *file_point_read = fopen(filename_or_path,"r"); char buffer[100]={0x0}; //读取到buf缓存中 int readLenght = fread(buffer,sizeof(char),100,file_point_read); printf("%s ",buffer); fclose(file_point_read); return0; }
是的,你的情书 就这么被妹子打开看到了,虽然 ,内容很直白,但是效果还是很好的。
从上例可以看到,我们要操作某个文件,必须先使用fopen以某种方式将文件打开,这个东西叫文件打开的mode,百度一下,你就知道了。另外,在区分文本文件和2进制文件的系统中 ,在mode里加一个b是个不错的注意,但是在posix协议的linux系统下,似乎没什么作用。
以特定的mode开后,我们就可以进行特定的操作,这个操作与mode必须对应,比如你使用r打开的文件就无法使用write功能,或者无效。
常用函数二(api)
#include<stdio.h> int fseek(FILE *stream,long offset,int whence); long ftell(FILE *stream); void rewind(FILE *stream); int fgetpos(FILE *stream,fpos_t*pos); int fsetpos(FILE *stream,constfpos_t*pos);
文件流
文件流 本质上是一个结构体的指针类型,FILE在头文件stdio中 定义。是的,所有的文件操作其实都是在操作这个流,这个概念到了C++中就直接使用了stream这个单词了,如果我早一点知道流这个概念,学期C++就不会那么蒙蔽了,IO操作的本质都是流概念。
废话不多说,除了读写,我们还可以怎样操作流呢,流可以类比成水流,我们可以获取它流到的位置,以及在特定的流位置进行操作。
当我们对文件流进行了读取或者写入操作后,文件流的指示器将发生位置改变,给个比喻,就是我作为领导 派遣一名小兵去巡视 河流,这个小兵一边巡视,其位置也是要随着河流的流向而变化的。这个小兵就是 文件流的指示器。那么如果我想要重新巡视一次,那就就得将小兵安排到河流的开始,或者我想要从某个位置开始巡视,也只是要将该小兵安排到河流对应的位置即可。
- show me the code directly
-
//一个类似的例子 #include<stdio.h> #include<string.h> #include<stdlib.h> int main(int argc,char* argv[]) { constchar* fileName ="disk.txt"; char*toWritebuff ="this is me Stultz lee"; FILE *fp = fopen(fileName,"w"); if(fp == NULL) { perror("file read"); return0; } int writeLenght = fwrite(toWritebuff,sizeof(char),strlen(toWritebuff),fp); fclose(fp); fp = fopen(fileName,"r"); char buffer[1024]={0x0}; int readLenght = fread(buffer,sizeof(char),1024,fp); printf("%s ",buffer); //使用ftell找到当前小兵的位置,它此时到了河流的尽头 int index = ftell(fp); printf("%d ",index);//得到21 //fseek 地点为SEEK_SET,;偏移量为0 时 与rewind意义相同,//都是要将该小兵放到河流的开头去 //fseek(fp,0,SEEK_SET); rewind(fp); index = ftell(fp); //int readLenght = fread(buffer,sizeof(char),1024,fp); printf("%d ",index);//得到0 memset(buffer,0,1024); readLenght = fread(buffer,sizeof(char),1024,fp); printf("%s ",buffer); #if 0 fseek(fp,-1,SEEK_SET); index = ftell(fp); //int readLenght = fread(buffer,sizeof(char),1024,fp); printf("%d ",index);//得到0 fseek(fp,1,SEEK_END); index = ftell(fp); //int readLenght = fread(buffer,sizeof(char),1024,fp); printf("%d ",index);//得到22 fseek(fp,-1,SEEK_END); index = ftell(fp); //int readLenght = fread(buffer,sizeof(char),1024,fp); printf("%d ",index);//得到20 #endif return0; }
备注 int fgetpos(FILE stream, fpos_t pos);
int fsetpos(FILE stream, const fpos_t pos);
使用不多,fpos_t可能是一个复杂的结构体,使用fseek,ftell,足以完成大部分文件流的偏移量转换工作,我们没必要把问题搞复杂。
以上是最简单的文件操作,适合基础入门,后面的文章,我将结合多线程的文件操作和网络编程来深入学习文件操作。记住,在linux中,一切都是文件 ,但是 我们不直接使用linux的 系统调用,比如open,write ,read等,而是使用fopen,fread,fwrite等函数,根本原因在于 系统调用会直接性的与 内核交互,这在多次的操作中 ,反而没有库函数来的效率高。