C语言学习笔记
文件操作
文件操作也很简单,分为三步走:打开文件、操作文件、关闭文件
文件操作fopen
-
函数原型
FILE* fopen (const charfilename, const char* mode);
-
原理:在物理内存中开辟一块空间,将磁盘中文件的内容复制过来,我们操作的就是复制来的这一份,本质就是一大串宇符串。操作完复制的这一份,要更新到磁盘空间,最终才能被修改。
fclose
就是更新的作用相当于保存文件。 -
函数的返回值是FLLE类型(本质是个结构体),也就是反回了文件的指针,也就是物理内存上的这块空间的首地址。
-
参数1是文件路径,这也分为绝对路径和相对路径。
-
参数2是文件的打开方式:分为文本形式和二进制形式。文本形式关键字如下所示:(注意写参数时都要带上双引号)
"r":只读,通过这种形式打开文件,文件就只能读取、不能修改。 注意:文件必须存在,否则fopen执行失败 如果文件本身是只读属性,那就只能用r打开。 "rt",t是text的缩写,文本格式,也就是rt和r相同,下同 "w":可读可写,但是是擦除写,比如文件原来有内容,w打开就会把文件擦除,重新按照咱们的意愿写入新数据。 注意:文件不存在时,会创建文件 "a":可读可写,接着写,比如文件有内容,打开文件内容正常,写入新内容,会在原有的结尾上接着写。 注意:文件不存在时,会重新创建文件 "r+":可读可写,通过这种形式打开文件,可读可写。 注意:文件必须存在,不存在fopen执行失败 "w+":跟w一样 "a+":跟a一样
- 注意文件打开失败时返回值是
NULL
。 - 注意又打开就有关闭,文件关闭函数是
fclose(pFile);
其参数就是要关闭文件的地址,意义是保存并关闭,注意他有保存的功能。
二进制模式
-
这些参数除了写法不一样,注意点和文本模式基本相同
"rb":二进制的只读形式 "wb":二进制的可读可写形式 "ab":二进制的接着写形式 "r+b","rb+":二进制的可读可写 "w+b","wb+"; "a+b","ab+";
fopen_s和errno_t
- 函数原型:
errno_t fopen_s(FILE** pFile, const cahr* filename, const char* mode);
这个函数功能是和fopen一样的,区别就是函数1,fopen通过返回值返回文件的指针,fopen_s通过参数1返回文件指针,它的返回值作为错误码返回。其中errno_t是int类型重命名。 - 既然errno_t的返回值类型是返回错误码,那我们就可以用它来查找错误信息。
fwrite写入数据
-
操作文件分为两种:读和写。也分为了两组函数,分别执行读写功能。
写 一次写入指定字节数:fwrite 一次写入一行:fputs 格式化写入:fprintf 读 一次都指定字节数:fread 一次读一行:fgets 格式化读:fscanf
-
通常他们都是一一对应着,成对的出现的,这样怎么写入就怎么读取,如果按照A的方式写入,再按照B的方式读取,虽然也能读,但是可能要有一些辅助操作在里面。
-
这三组函数完全能够互相代替,实际中,根据需要,哪个方便用哪个,当然也可以一直用fwrite。
-
函数原型:
size_t fwrite(const void*buffer,size_t size,size_t count,FILE*stream);
-
在上述程序中,创建了新文件
qwe.txt
,我们再打开该文件后可以看到,程序中被写入了Hello,Lancibe
注意这里是有一个空格的,这也就是strlen +1的结果。 -
参数1:写入文件的数据首地址,可以是字符串,可以是数组,可以是结构体。
-
参数2、参数3:这两个参数相乘==写入的字节数,一般参数2写sizeof(类型),参数3写多少个该类型数据。
-
参数4:文件指针
-
返回值:实际写入的字符数,写入失败返回0;
检测错误:
a = fwrite(str,sizeof(char),strlen(str)+1,p);
a = errno;
- 注意在写文件时,可能会出现一些乱码,这跟系统默认的字符集不一样有关。其本质可以理解为是指针的偏移,因为多次使用fwrite时能正常写入数据。
- fwrite输入换行:在文本模式直接就加上
\n
就可以,或者也可以单独定义一个字符串(字符):char *strn = "\n"; char strn = '\n';
二进制模式时换行使用\r\n
,所以其实二进制模式和文本模式区别不大,就是二进制模式使用wb,rb,ab
等,其换行要使用\r\n
fread函数介绍
- 函数原型:
size_t fread(void *buffer,size_t size,size_t count,FILE *stream);
他的参数和fwrite基本相同,只是在第一个参数中,fwrite函数对原数据不进行修改,所以用了const修饰,而fread函数中我们是要把文件中的数据读出来,所以要修改原来的数据。 - 注意读文件的时候一定不要用w(fopen的第二参数),因为w是擦除写,他会直接把文件中原来的所有内容删除。
- 参数1:是我们自己的字符数组,文件读出来的内容装在这里。
- 参数2*参数3:一次都出来的字节数,比如
sizeof(struct),3
这样就直接三组数据,每组是sizeof大小,逻辑上清晰。 - 参数4是文件指针,
- 返回值:返回我们实际读出的字节数(还有一种情况:一下读超过了已有字节数,返回0;读的小于等于文件字节数,返回值1;通过这个01变量,我们就可以把它放进循环了,这个返回值作为条件。)
- 在上述程序中,假设原文件的数据是1234567,这样的打印结果是
12345676
,原因是两位两位读取,最后读到了7,由于上次数据的残留,最终会读出76。
文本模式与二进制模式深入
- 我们可以通过使用文本模式读取文件中的换行号,并且用数组装,会发现它是a,对应的ASCII值就是10,也就是
'\n'
;相似的,如果用二进制模式正确的读取,会发现返回值是2,也就是读到了两个字符,分别是d和a,也就是ASCII中的"\r\n"
。其实在操作系统中,系统会自动将我们文本模式中的'\n'
转化为"\r\n"
,也就是二进制模式。 - 选择方法;考虑到移植性,文本模式更合适,这是因为在linux下,文件行末结尾就是
'\n'
,所以二进制模式会出问题。 - 介绍获取文件结尾标识函数:
int feof(FILE *stream);
,参数是文件指针,返回值是到了结尾返回非0的数,没到结尾返回0,这点和我们平常使用的函数不太一样,所以在作为循环条件时,要注意前面加!
文件读写结构体
- 首先声明,只有
fread fwrite
能对结构体进行读写。 - 这样的程序中创建的文件里面会很自然地出现乱码,这是因为结构体里面涉及到内存对齐,所以没有使用到的字节里面就赋了默认的初始值。
- 如果在用一个新的,成员相同的结构体来读取文件中的数据,结果会被完美的读取出来。
fputs和fgets
- 函数原型:
int fputs(const char* str, FILE*stream);
char* fgets(char*str , int n, FILE* stream);
- fputs介绍:参数1:输入的字符串地址,参数2:文件指针。返回值:成功返回0,失败返回EOF。
- 这里就可以看出这两个函数的局限性,只能写入/读取char*。
- fgets介绍:从文件中读出一行数据,参数1:读出来的数据装的位置str,参数2:最大的读取两,不要超过参数1的长度(这里也是为了保护),参数3时文件指针。其返回值就是str的地址。
fprintf和fscanf
fprintf
用法和printf
一样,第一个参数放文件指针,之后和printf用法就完全一样了。fprintf(pFile, "%d,%s,%.3lf",12,"hello,Lancibe",123.12);
,注意,由于和printf使用方式基本一样,所以这样文件中写入的内容应该是12,hello,Lancibe,123.120
fscanf
用法也和sacnf
差不多,第一个参数放文件指针,后面和scanf用法完全一样。但是最好将变量进行初始化为0,不然系统可能会报错
int a = 0;
char str[20] = {0};
double d = 0.0;
fscanf(pFile, "%d,%s,%.2lf", &a, str ,&d);
- 如果是想读取fprintf写入的数据,一定要对应好引号里面的所有内容,一丁点差错都会导致读取错误。
- 这些函数都会有升级版本,可以自己通过转定义去查。
fseek和ftell
- 函数原型:
int fseek(FILE *stream, long offset, int origin);
long ftell(FILE *stream);
- fseek函数作用是设置文件指针的位置。
- 参数1:文件的指针,参数2:设置文件指针的位置(相对位置),参数3:具体位置。(注意下面代码中参数二的后缀是L不是1,带上l是因为他是long型变量)
fseek(pFile,0l,SEEK_SET); 设置文件指针指向头
fseek(pFile,10l,SEEK_SET); 设置文件指针指向从头开始向后走10个字节
fseek(pFile,10l,SEEK_CUR); 设置文件指针在当前位置再向后走10个字节
fseek(pFile,0l,SEEK_END); 设置文件指针指向结尾
fseek(pFile,-10l,SEEK_END); 设置文件指针指向结尾向前10个字节
- 返回值是int类型的,成功,返回0,失败返回非0值。
- ftell函数:参数1是文件指针,返回值是文件指针当前位置。也就是说,这两个函数是经常配合使用的。
- 常用技巧:
fseek(pFile, 0l, SEEK_END);a = ftell(pFile);printf("%d",a);
这样一组合,就能打印出文件所有的字节数(这里是没有下标的那种+1-1的,是多少就是多少)。
文件关闭fclose
- 函数原型:
int close fclose(FILE *stream);
参数是文件指针,作用是关闭文件,更新到文件中,将内存空间释放。 - 注意它的功能可以理解为保存,这点很重要。
- 有点像
malloc
申请堆区空间之后使用free
释放。