TIPS
1. 文件是不是二进制文件,不是后缀说了算,而是内容说了算
2.
文件的随机读写
文件的随机读写也就是说我指哪打哪
fseek() 人为调整指针指向的位置
1. 根据文件指针FILE*的当前位置和你给出的偏移量来让它这个文件指针呢定位到你想要的位置上去。
2. 就是说我想让文件指针偏移到哪里,你就给我偏移到哪里
3. 它这个函数有三个参数:FILE* stream,long int offset(偏移量),int origin(起始位置)
4. 其中第三个参数int origin是有选项的。关于这个参数有三个选项:SEEK_SET,就是说从文件的起始位置开始算起;SEEK_CUR,从当前文件指针的位置算起;SEEK_END,就是说从文件的末尾开始算起。
补充:文件指针的正常运走
1. 一旦打开文件,有个闪烁的光标(其实就是说刚开始打开文件的时候,文件指针是默认指向第一个字符的),这是最开始的状态。
2. 然后当你用fgetc()输入一个字符后,此时文件指针就不指向第一个字符了,往后走一步指向第二个字符去了。
3. 再用fgetc()不断去读,文件指针就不断往后偏移,一个一个字符不断读下去。这就是顺序读写,那如果说你想控制顺序跳过字符或者回去读之类的.....
5. 这时候就用fseek去手动调整指针指向的位置,有三种写法。随着你第三个参数的不同,偏移量也不同(往左偏移,偏移量为负数;往右偏移,偏移量为正数)。
6. 然后不管你怎么去调整,默认的"读一下,往右偏移一个字符"这个铁律永远都在。但不管怎么说,fseek就是能调整指针指向的位置,读一位的话往右偏移一位那就让它偏呗。
//演示fseek()
int main()
{
FILE* pf = fopen("test.txt","r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
//正常
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
//调整1
fseek(pf, 7, SEEK_SET);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c\n", ch);
//调整2
fseek(pf, -5, SEEK_END);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c\n", ch);
//
fclose(pf);
pf = NULL;
return 0;
}
ftell() 当前指针位置相当于起始位置的偏移量
1. 如果我用fseek()的时候,里面内容很多,我弄着弄着也不知道偏移量多少了怎么办?
2.ftell就是来返回当前文件指针相对于起始位置的偏移量。这样子你可以得到偏移量,然后用fseek乱弄了。
//演示ftell()
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
int i = 0;
for (i = 0; i < 3; i++)
{
fgetc(pf);
}
//计算当前偏移量
int a = ftell(pf);
//调整
fseek(pf, 7 - a, SEEK_CUR);
//
for (i = 0; i < 9; i++)
{
fprintf(stdout, "%c", fgetc(pf));
}
fclose(pf);
pf = NULL;
return 0;
}
rewind() 让指针回到起始位置
1. 让我们的文件指针回到起始位置,当然了,fseek本身就具备这个能力。然而rewind也可以做到。
//演示rewind()
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
int i = 0;
for (i = 0; i < 3; i++)
{
fgetc(pf);
}
rewind(pf);
//
for (i = 0; i < 16; i++)
{
fprintf(stdout, "%c", fgetc(pf));
}
fclose(pf);
pf = NULL;
return 0;
}
文本文件与二进制文件
1. 根据数据的组织形式,数据文件(与它同级的是程序文件)又被称为文本文件与二进制文件。
2. 我们知道,数据在电脑内存里面是以二进制补码形式存储,如果对内存里面的数据(纯纯的二进制)不加任何转换输出到外存(比如说输出到硬盘上啊文件里面去,反正就是写到文件里面去),这个时候就叫做二进制文件。
3. 如果要求在外存上以ASCII码值的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。(把字符对应的ASCII码值存到文件里面去,以ASCII码值的形式存储)。
4. 当然,这里面还有一个大小端的问题,如果你在内存里面以小端形式存储,那么也会直接以小端的形式写到文件里面去
实例演示
1. 比如说对于一个数值10000。如果我要把它存起来。我们知道这个10000在内存里面就是00......0010011100010000。如果说我们把这个二进制序列不做任何转换直接存到文件里面去,此时这个文件就是二进制文件。
2. 如果说我们把10000的每一位都当成字符即:"1","0","0","0","0"。然后把每个字符对应的ASCII码值存到文件里面去。这时候这个文件就是文本文件。
文件读取结束/读取失败or碰到EndOfFile
1. 这个是读取文件的时候非常非常重要的知识点。
2. 我们不管用前面讲的哪个函数fgetc,fgets,fread,fscanf...,这些都是在读取文件。一般来说都是正常的,比如fgetc()返回ASCII值,fgets()返回字符串地址,fread()返回读到的实际元素个数
3. 但是有时候问题来了,fgetc()返回EOF,fgets()返回NULL,fread()返回读到的实际元素个数<我参数指定的元素个数,这时候就是读取文件结束
文件读取结束
对于文本文件的读取(fgetc,fgets):对于fgetc()如果读取结束就会返回EOF,对于fgets()如果读取结束就会返回NULL(空指针)。
对于二进制文件的读取(fread):fread我们知道在使用的时候我会在参数指定我要读取几个元素,每个元素几个字节。但实际上比如说我参数指定了读9个元素,但它只读到了8个,这时候就会返回8,就是说它的返回值是你实际读到几个就返回几。所以我只需要去判断一下fread的返回值是否小于参数指定的要读的个数,我就能知晓是否文件已经读取结束。
文件的读取结束之后,接下来就需要我去判断一下读取结束的原因。是因为碰到了文件末尾结束,还是因为读取失败而导致结束
前提:文件读取结束了,想知道读取结束的原因.....
feof()与ferror()是用来判断结束原因的
ferror() 判断是不是碰到了异常错误导致读取结束
1. 判断这个文件结束的原因是不是因为读取的时候碰到了错误。
2. ferror()如果返回真,就说明是因为IO错误结束的(也就是说文件在读取过程中出错了),这是一种外因异常结束。
feof() 判断是不是碰到了文件结尾而正常读取结束
1. 可以用它去判断一下。
2. feof()如果返回真,就说明文件正常读取,在读取的时候碰到文件结束标志EOF而结束的。
文件缓冲区
1. ANSIC标准采用“缓冲文件系统”来处理数据文件。
2. 所谓“缓冲文件系统”,指系统自动地在内存中为程序中正在运行的每一个文件开辟一块“文件缓冲区”。
(文件就是在电脑磁盘里面)
3. 内存数据输出/写到磁盘里面,其会先被送到内存中的输出缓冲区,装满缓冲区后再一次性送到磁盘里面/或者说我主动刷新一下缓冲区里面的数据然后放到硬盘里面去。
(然后假设我缓冲区一直没满,但是我要关闭文件了,这时候没关系,系统会刷新一份缓冲区的数据,这时候不管满没满了,文件都要关闭了,直接把数据放到文件里面去,然后才关闭文件,所以fclose本身关闭文件的时候也会刷新缓冲区的)
4. 如果从磁盘里面往内存输入/读数据,数据也是先放到缓冲区。充满缓冲区后,然后再从缓冲区里面逐个地将数据送到程序数据区(程序变量等)。
5. 缓冲区大小根据C编译系统决定。
6. 缓冲区也是在内存里面的,当然了,摸不着看不到的。
证明缓冲区的存在