标准IO(2)、文件IO
一、文件IO和标准IO的概念
1.文件I/O
文件I/O是操作系统封装了一系列open、close、write、read等API函数构成的一套用来读、写文件的接口供应用程序使用,通过这些接口可以实现对文件的读写操作,但是效率并不是最高的。
文件I/O是采用系统直接调用的方式,因此当使用这些接口对文件进行操作时,就会立刻触发系统调用过程,即向系统内核发出请求之后,系统内核会收到执行相关代码处理的请求,决定是否将操作硬件资源或返回结果给应用程序。
2.标准I/O
标准IO:应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO有一系列的C库函数构成(fopen,fclose,fwrite,fread),这些标准IO函数其实是由文件IO封装而来的(fopen内部还是调用了open);,我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf中。因此,标准I/O封装了底层系统调用更多的调用函数接口。
文件I/O和标准I/O的本质区别:
1)缓冲区:标准I/O函数接口在对文件进行操作时,首先操作缓存区,等待缓存区满足一定的条件时,然后再去执行系统调用,真正实现对文件的操作。而文件I/O不操作任何缓存区,直接执行系统调用。
2)系统开销:使用标准I/O可以减少系统调用的次数,提高系统效率。例如,将数据写入文件中,每次写入一个字符。采用文件I/O的函数接口,每调用一次函数写入字符就会产生一次系统调用。 而执行系统调用时,Linux必须从用户态切换到内核态,处理相应的请求,然后再返回到用户态,如果频繁地执行系统调用会增加系统的开销。
3)执行效率:采用标准I/O的函数接口,每调用一次函数写入字符,并不着急将字符写入文件,而是放到缓存区保存,之后每一次写入字符都放到缓存区保存。直到缓存区满足刷新的条件(如写满)时,再一并将缓存区中的数据写入文件,执行一次系统调用完成此过程,这样便很大程度地减少了系统的调用次数,提高了执行效率。
二、标准IO特点
特点
1、有缓冲机制,通过缓冲机制减少系统调用的次数,提高效率
2、围绕流进行操作,流用FILE *描述,FILE是一个保存文件信息的结构体
3、默认打开了三个流,stdin(标准输入)、stdout(标准输出)、stderr(标准错误)
缓存区
1、行缓存:1k大小、和终端相关、主要用于人机交互stdout
刷新缓存的条件:
- 程序正常退出
- \n刷新缓存
- fflush强制刷新
- 缓存区满刷新
2. 全缓存:4k大小、和文件相关
刷新缓存的条件:
- 程序正常退出
- fflush强制刷新
- 缓存区满刷新
3. 不缓存:没有缓存区/错误信息,不对数据缓存直接刷新
二进制读写
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件流读取多个元素
参数: ptr :用来存放读取元素size :元素大小 sizeof(数据类型)nmemb :读取对象的个数stream :要读取的文件
返回值:成功:读取对象的个数读到文件尾: 0失败: -1
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按对象写
参数:同上
返回值:成功:写的元素个数失败 :-1
Fread和fwrite函数注意:
1)两个函数的返回值为:读或写的对象数
2)对于二进制数据一次读或写整个结构。
文件定位操作
int fseek(FILE *stream, long offset, int whence);
功能:文件的定位操作
参数:stream:文件流offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移whence:相对位置:SEEK_SET:相对于文件开头SEEK_CUR:相对于文件当前位置SEEK_END:相对于文件末尾
返回值:成功:0失败:-1
注:当打开文件的方式为a或a+时,fseek不起作用
ftell 函数
long ftell(FILE *stream);
ftell()
函数的作用是 获取文件的 当前指针位置 相对于 文件首地址 的 偏移字节数 ;
使用场景 : 随机方式存取文件时 , 使用 fseek 函数来回移动指针 , 不容易确定当前指针位置 , 通过调用 ftell
函数确定指针位置 ;
int main(int argc, char const *argv[])
{FILE * fp = fopen("2.txt","r");if(NULL == fp){return 1;}
// 使用 ftell 函数获取当前指针位置fseek(fp,0,SEEK_END);long size = ftell(fp);printf("size %ld\n",size);fclose(fp); return 0;
}
rewind()函数
将读写位置指针重置到文件开头。
void rewind(FILE *filepointer);
二、文件IO
文件IO的特点
-
无缓冲机制:文件IO直接调用系统内核进行数据传输,不经过操作系统内核的缓存。
-
系统调用:每次文件IO操作都会触发系统调用,系统内核会处理相应的请求并返回结果。
文件IO的基本操作
打开文件:使用open函数打开一个文件,返回一个文件描述符(file descriptor,简称fd),用于后续的读写操作。
int fd = open("1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);if (-1 == fd){fprintf(stderr, "open error\n");return 1;}
读文件:使用read函数从文件中读取数据。
int fd = open("1.txt", O_RDONLY);
if (-1 == fd)
{fprintf(stderr, "open error\n");return 1;
}
char buf[1024] = {0};
ssize_t ret = read(fd,buf,sizeof(buf));
printf("readret:%ld %s\n", ret,buf);
close(fd);
写文件:使用write函数将数据写入文件。
int a = 12312;
int fd = open("1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (-1 == fd)
{fprintf(stderr, "open error\n");return 1;
}
char buf[1024] = "hello";
ssize_t ret = write(fd, buf, strlen(buf));
printf("write ret:%ld\n", ret);
close(fd);
三、文件权限
常见的Linux文件权限
444 -r--r--r--
600 -rw-------
644 -rw-r--r--
666 -rw-rw-rw-
700 -rwx------
744 -rwxr--r--
755 -rwxr-xr-x
777 -rwxrwxrwx
用户分组权限概念(如:777 -rwxrwxrwx)
从左至右:
- 最左侧1位d表示文件夹,l表示连接文件,-表示文件
- 2-4位数字代表文件所有者的权限
- 5-7位数字代表同组用户的权限
- 8-10数字代表其他用户的权限