文件原理解析
C文件概述
程序执行时称为进程,进程运行过程中的数据均在内存中。 需要存储运算后的数据时,需要使用文件。这样程序下次启动后,就可以直接从文件中读取数据。(之前的程序每次运行都需要手动输入数据)。 文件是指存储在外部介质(如磁盘、磁带)上的数据集合。操作系统( Windows、Linux、Mac 等)是以文件为单位对数据进行管理的。 实际上输入缓冲区和输出缓冲区是同一个区域。 缓冲文件系统:系统自动地在内存区为每个正在使用的文件开辟一个缓冲区。用缓冲文件系统进行的输入/输出称为高级磁盘输入/输出。 非缓冲文件系统:系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。用非缓冲文件系统进行的输入/输出称为低级输入/输出。 缓冲区原理: 缓冲区是一段内存空间,分为读缓冲、写缓冲。
::: tip c语言缓冲的三种特性: (1)全缓冲:在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写操作。 (2)行缓冲:在这种情况下,当在输入和输出中遇到换行符时,将执行真正的I/O操作。这时,我们输入的字符先存放到缓冲区中,等按下回车键换行时才进行实际的I/O操作 典型代表是标准输入缓冲区 (stdin)和标准输出缓冲区(stdout)。 (3)不带缓冲:也就是不进行缓冲,标准出错情况(stderr)是典型代表,这使得出错信息可以直接尽快地显示出来。 :::
文件指针
每打开一个文件时,都会得到一个FILE*类型的文件指针fp,通过该文件指针对文件进行操作。 FILE是一个结构体类型,如下: ::: warning 每读取一个字符后,ptr会自动指向下一个字符。 :::
文件打开及关闭!
fopen函数用于打开由fname(文件名)指定的文件,并返回一个关联该文件的流(即fp指针)。如果发生错误,那么fopen返回NULL。mode(方式)用于决定文件的用途(如输入、输出等)。 常用mode参数: fclose函数用于关闭给出的文件流,并释放已关联到流的所有缓冲区。fclose执行成功时返回0,否则返回EOF(-1)。 fputc函数用于将字符ch的值输出到fp指向的文件中,如果输出成功,那么返回输出的字符;如果输出失败,那么返回EOF。 fgetc函数用于从指定的文件中读入一个字符,该文件必须是以读或读写方式打开的。如果读取一个字符成功,那么赋给ch。如果遇到文件结束符,那么返回文件结束标志EOF。 fgetc每读到一个字符,都会自动指向下一个。 fgetc函数用于从指定的文件中读入一个字符,该文件必须是以读或读写方式打开的。如果读取一个字符成功,那么赋给ch。如果遇到文件结束符,那么返回文件结束标志EOF。 fgetc每读到一个字符,都会自动指向下一个。 代码如下:
#include <stdio.h>
int main()
{
FILE*fp;
fp=fopen("file.txt","r+");
if(NULL==fp)
{
perror("fopen");
return -1;
}
char c;
// c=fgetc(fp);
// printf("%c ",c);
// c=fgetc(fp);
// printf("%c ",c);
while((c=fgetc(fp))!=EOF)
{
printf("%c ",c);
}
c=fputc('W',fp);
if(-1==c)
{
perror("fputc");
return -1;
}
fclose(fp);
return 0;
}
h e l l o
::: warning 上述代码中同时读写的操作是在Clion实现的,VS中实现同时读写还需要其他操作。 :::
文件读写
fgetc和fputc每次只能读写一个字符。
fread和fwrite
其中buffer是一个指针,对fread来说它是读入数据的存放地址,对fwrite来说它是输出数据的地址(均指起始地址);size是要读写的单个成员的字节数;count是要进行读写多少size字节的数据项;fp是文件型指针。 fread函数不知道存储读取内容的大小,只能传递要存储读取内容的空间大小,即count。 fwrite函数传递写入数据的实际大小,即num。 fread函数的返回值是读取的内容数量,fwrite函数写成功后的返回值是已写对象的数量。 ::: warning fwrite写入后光标移动到最后,再fread读取时读不到内容,所以不能同时使用。 :::
代码如下:
#include <stdio.h>
#include <string.h>
int main() {
char buf[20]="Hello\nWorld";
FILE*fp;
int ret;
fp=fopen("file.txt","r+");
if(-1==fp)
{
perror("fopen");
return -1;
}
//ret=fwrite(buf,sizeof(char),strlen(buf),fp);
char buf1[20]={0};
ret=fread(buf1,sizeof(char),sizeof(buf1),fp);
printf("%s",buf1);
fclose(fp);
return 0;
}
Hello
World
在文本方式下,向文本文件中写入“\n”时实际存入磁盘的是“\r\n”,共12字节所有的接口调用都是Windows的系统调用,这是Windows的底层实现所决定的 (Mac和Linux不会)。 ::: tip 以文本方式写入,一定要以文本方式读出,遇到“\r\n”时底层接口会自动转换为“\n”,因此用 fread函数再次读取数据时,得到的依然是“hello\nworld”,共11字节。 ::: 如果把上述代码fopen函数中的“r+”改为“rb+”,即改为二进制方式,向磁盘写入11字节时,磁盘实际存储的就是11字节,打开该文件会发现没有换行,即helloworld是连在一起的,中间没有换行符,原因是txt文本编辑器必须遇到“\r\n”时才进行换行操作。 以文本方式写入的内容要以文本方式读取,以二进制方式写入的内容要以二进制方式读取。
fgets和fputs
fgets在到达行末时停止,fgets成功时返回str(字符串) ,失败时返回NULL,读到文件结尾时返回NULL。 fputs函数把str(字符串)指向的字符写到给出的输出流。成功时返回非负值,失败时返回EOF。 fgets一次读取一行,包括行尾的换行符。
文件位置指针偏移
fseek函数可以改变文件的位置指针。 *stream:文件类型指针。即FILE结构体中的ptr指针。 offset:位移量。 origin:起始点。 起始点:
位移量是以起始点为基点向前移动的字节数,一般要求为long型。 fseek函数调用成功时返回0,调用失败时返回非0。
ftell函数返回stream当前的文件位置(位置指针距离文件开头的位置),发生错误时返回-1。