未完

6.0 文件基本操作

对文件的操作我们所要采用指针,C语言创建之初是为了写unix系统,也就是后来的Linux系挺,它对文件是流的操控。
需要注意,如果使用完需要:fclose();
fclose 不光是关闭文件,还会把缓冲区的内容写入到文件。
缓冲区的作用:
缓冲区的作用实际上是用来包含我们的硬件的。
所有的磁盘都是有寿命限制的,每次读写对磁盘是有伤害的。
缓冲区是先集合要写的内容,然后统一写入进去

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main(void) {

FILE* fp = NULL; // 可以将指针变量看成一个钥匙
fp = fopen("FILE\\Hello.txt", "w+"); // 第一个参数是"文件路径和文件名称" 第二个参数是模式 开门
if (fp == NULL) {
return -1;
}

fclose(fp); // 关门
fp = NULL;

printf("\n");
system("pause");
}

fopen() 的模式字符串

fopen()参数说明:第一个参数是文件名称或文件路径,第二个则是文件模式字符串。

模式字符串 含义
“r” 以读的模式打开文件
“w” 以写的模式打开文件,把现有文件的长度截为0(清除内容),如果文件不存在,则创建一个新文件
“a” 以写的模式打开文件,在现有文件末尾添加内容,如果文件不存在,则创建一个新文件
“r+” 以更新模式打开文件(即可以读写文件)
“w+” 以更新模式打开文件(即,读和写),如果文件存在,则将其长度截为0(清楚内容),如果文件不存在,则创建一个新文件
“a+” 以更新模式打开文件(即,读和写),在现有文件的末尾添加内容,如果文件不存在,则创建一个新文件;可以读整个文件,但只能从尾部添加内容。
“rb”、”wb”、”ab”、”ab+”、”a+b”、”wb+”、”w+b”、”ab+”、”a+b” 以上个模式类似,但是以二进制模式,而不是文本模式打开文件
“wx”、”wbx”、”w+x”、”wb+x”或”w+bx” (C11)类似非x模式,但是如果文件已经存在或以独占模式打开文件,则打开文件失败。

6.0.1 文件写入内容和文件缓冲区

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main(void) {
FILE* pf = NULL;
pf = fopen("FILE\\World.txt", "w+");

if (pf == NULL) {
return -1;
}

fputs("Hello World", pf);

// 断点 去文件里看看有没有数据,这样就可以看缓冲区

/**
* fputs不是把内容写入文件当中,而是写入到缓冲区。
* fclose 不光是关闭文件,还会把缓冲区的内容写入到文件。
* 缓冲区的作用:
* 缓冲区的作用实际上是用来包含我们的硬件的。
* 所有的磁盘都是有寿命限制的,每次读写对磁盘是有伤害的。
* 缓冲区是先集合要写的内容,然后统一写入进去
*/

fclose(pf);
pf = NULL;

printf("\n");
system("pause");
}

6.0.2 文件重定向

标准输入和标准输出
C的出现就是为了写系挺就是unix诞生的后来unix发展出众多系统(linux)
而系统操作最多的就是文件,以前用C语言的开发者都说一切皆是文件,这句话是对的。
因为C特殊就特殊在它把输入输出都当作文件,输入输出就是键盘和屏幕。C语言把所有的东西都看作是一个文件。
把键盘看作一个文件,把屏幕也看作是一个文件。打印机也看作一个文件,C语言的世界里只有文件。
重定向就是无论你是什么(软件|硬件),都可以相互转换。
重定向就是本来该显示在这里的东西可以显示在另一个地方。
重点:C语言一切皆文件。

文件重定向

Unix、Linux和当前的 DOS 版本都能够重定向输入和输出。输入重定向可以使程序能够使用文件代替键盘作为输入,输出重定向则使程序能够使用文件代替屏幕输出。
输出重定向就是用文本文件代替屏幕当作程序的输出,”>” 运算符是另一个重定向运算符。假设我们要将键盘输入的数据发送至一个名为Test,.txt的文件。通过下面这条语句就可以完成:
Reput.exe> Test.text。
该运算符会导致建立一个名为Test.txt的新文件供我们使用,然后将Reput.exe的输出(也就是说,我们嵌入的字符的副本)重定向到该文件。该重定向将stdout从显示设备(屏幕)重定向到Test.txt文件。
如果你已经有一个名为Test.txt的文件,则通常会删除该文件,然后再用新的文件代替。

重定向要点

重定向运算符是将一个可执行程序与一个数据文件链接起来,该运算符不能用于一个数据文件与另一个数据文件的链接,也不能用于一个程序和另一个程序的链接。
使用这些运算符时,输入不能来自一个以上的文件,输出也不能定向至一个以上的文件。
“>>” 运算符用累加的方法将数据输出到指定的文件上,不会覆盖已经有的数据,是在原基础上追加数据。

gets 函数的作用

gets用来从标准设备读取字符并存放到参数s所指向的内存空间,直到出现换行字符或读到文件尾为止。
注意该函数目前C语言不推介使用了。C99 标准时候,委员会认为这个函数过于危险,很容易造成内存泄露(char ch[10] = {0}; 在控制台输入大于定义的值它不会报错,运行完成后程序会自动崩溃),但以前的C语言代码都是用了这个函数,如果不用了,以前的代码就无法维护了,所以委员会支持该函数,但不建议使用。C11 标准认为可以废弃以前的代码将这个函数废弃。C11 建议放弃。但目前gets这个函数并没有废弃,还是可以使用,但建议放弃,C11 委员会推出了fgets供用户使用。(哈哈哈,C语言标准每年都很逗)

6.0.3 文件重定向二

C语言把所有的设备当做文件来处理
C语言在进行文件操作时遵循如下步骤:打开-> 读写操作-> 关闭
C语言在程序中建立一个文件,本身就是结构体,然后返回的是一个结构体指针,文件指针是由操作系统来管理的。

文件指针的详细信息

FILE 类型详细底层实现

/**
* C语言通过该结构体描述文件
*/

struct _iobuf {
char* _ptr; // 当前缓冲区内容指针
int _cnt; // 缓冲区还有多少字符
char* _base; // 缓冲区的起始地址
int _flag; // 文件流的状态,是否错误或结束
int _file; // 文件描述符
int _charbuf; // 双字节缓存,缓存两个字节
int _bufsiz; // 缓冲区大小
char* _tmpfname;// 临时文件名
};
typedef struct _iobuf FILE;

标准输入与标准输出

通俗来说,打开是获取文件结构、系统为文件分配缓存中的过程,不打开文件就不能对其进行读写,关闭是释放缓冲区和其他资源的过程,不关闭文件就会慢慢耗光系统资源。
我们在进行文件操作时,系统自动与3个标准设备文件联系,这3个文件无需打开和关闭,它们的文件指针分别是:
stdin:标准输入文件指针,系统分配为键盘。
stdout:标准输出文件指针,系统分配为显示器。
stderr:标准错误输出文件指针,系统分配为显示器。

gets 函数废弃的原因

gets() 函数简单易用,它读取整行输入,直至遇到换行符,然后丢弃换行符,储存其余字符,并在这些字符的末尾添加一个空字符”\0”,使其成为一个c字符串。它经常和puts函数配对使用。该函数用于显示字符串,并在末尾添加换行符。

问题在于gets()唯一一个参数是words,它无法检查数组是否装得下输入行,之前示例说过,数组名会被转换成数组的首元素的地址,因此gets()函数只知道数组的开始处,并不知道数组中可以放多少个元素。

如果输入的字符串过长,会导致缓冲区溢出(buffer overflow),即多余的字符超出了指定的目标控件。

fgets函数和gets函数的区别

fgets函数通过第二个参数限制读取字符的最大数量,如果该参数的值为n,那么fgets()将读入n-1个字符,或者读取遇到的第一个换行符为止。
fgets()函数读取到一个换行符,会把它存储在字符串中。这点与gets不同,gets()会丢弃换行符。
fgets()函数的第三个参数指明要读取的文件。如果读入从键盘输入的数据,则以stdin(标准输入)作为参数,该标识符定义在stdio.h文件中。

fgets()函数的语法:

fgets 是gets的替换版,三个参数:内存地址、可存储最大字节数、文件流
fgets(ch, 10, stdin);
这里第一个ch是我们用指针绑定的数组获取的数组指针,10则是绑定数组的数组大小,stdin是标准输入即表示键盘。
对应的还有一个输出叫:fputs()函数。

6.0.4 文件读取

fgetc 读取字符

从文件中读取一个字符,fgetc 只能读取窄字符。

feof的作用

检查文件流是否读到了文件尾。
函数说明:
feof用来检测是否读取到了文件尾,尾数stream 为 fopen() 所返回的文件指针。如果已经到文件尾,则返回非零值,其他情况返回0。
返回值:返回非零值代表已经到达文件末尾使用前面加上非。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main(void) {
char ch = 0;
FILE* fp = fopen("FILE\\World.txt", "r");
if (fp == NULL) {
return -1;
}

while (!feof(fp)) {
ch = fgetc(fp); // 获取,它一次只能读取一个字符
printf("%c", ch);
}

fclose(fp);
fp = NULL;

printf("\n");
system("pause");
}

6.0.5 C语言获取文件大小

获取文件大小方法一:简单不建议使用(容易出错)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main68(void) {
char ch = 0;
FILE* fp = fopen(“FILE\World.txt”, “r”);
if (fp == NULL) {
return -1;
}
int i = 0;

while (!feof(fp)) {
ch = fgetc(fp); // 获取,它一次只能读取一个字符
printf(“%c”, ch);
i++;
}

fclose(fp);
fp = NULL;
pringtf(“%d\s”,i);

printf(“\n”);
system(“pause”);
}
获取文件大小方法二

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

void main(void) {

FILE* pf = fopen("FILE\\World.txt", "rb");

if (pf == NULL) {
return -1;
} else {
/* 0代表偏移量 */
fseek(pf, 0, SEEK_END); // 文件指针移动到末尾
int length = ftell(pf); // 获取当前文件指针距离开头的长度
fclose(pf);
printf("%d\n", length);
pf = NULL;
return length;
}


printf("\n");
system("pause");
}

fseek 的作用

fseek() 用来移动文件流的读写位置。参数stream为已打开的文件指针,参数offset为根据参数whence来移动读写位置的位移数。
参数whence为下列其中一种:
SEEK_SET:从距文件开头,offset位移量为新的读写位置。
SEEK_CUR:以目前的读写位置往后增加offset个位移量。
SEEK_END:将读写位置指向文件尾后再增加offset个位移量。

当whence值为SEEK_CUR或SEEK_END时,参数offset允许负值出现,下列是比较特别的使用方式:
欲将读写位置移动到文件开头时:
fseek(FILE* stream,0,SEEK_SET)
欲将读写位置移动到文件尾时:
fseek(FILE* stream,0,SEEK_END);

函数返回值
当调用成功则返回0,若有错误则返回-1,error会存放错误代码

附加说明:
fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。