Linux 系统编程2:缓冲I/O(标准I/O)
前言:上一章介绍了LINUX系统调用的一些文件I/O函数,本章将继续学习C库中的标准I/O函数。
文件指针:标准I/O并不是直接操作文件描述符,他们有自己的唯一标识符---文件指针去操作.文件指针和文件描述符是一一映射的关系
1.打开文件
1). 通过fopen()打开,返回文件所映射的文件指针。
#include <stdio.h>
FILE* fopen(const char* path,const char* mode);
和open()函数类似,有文件路径和打开方式。mode有如下几种:
r:只读模式打开文件,流指针指向文件开始。
r+:可读模式打开,流指针指向文件开始。
w:只写模式打开,往里写东西,若文件存在,文件内容被清空,文件不存在则创建文件,流指针指向文件开始。
w+:可写模式打开文件,规则情况同w
a:追加模式打开文件,文件不存在则创建文件。流指针指向文件的末尾,所有人写的文件都是追加到文件的末尾。
FILE* stream;
stream=fopen("/etc/manifest","r");
//只读模式打开
2).可以通过函数fdopen()把一个已经打开的文件描述符(open()或网络编程函数创建的可以进行读写的文件描述符)转化为流。
#include <stdio.h>
FILE* fdopen(int fd.const char* mode);
但要注意的是:fdopen()的可能模式和fopen()的可能模式相同,而且必须和最初打开文件描述符的模式相匹配。fdopen()里指定的写模式不会清空原文件内容。
注意文件描述符并没有被复制,而只是关联了一个新的流,关闭了流也会关闭文件描述符。如下例子。
FILE* stream;
int fd;
fd=open("/home/user/1.txt",O_RDONLY);
if(fd==-1){
........
}
stream=fdopen(fd,"r");
if(!stream)
/*error*/
3).关闭流
#include <stdio.h>
int fclose(FILE* stream);
int fcloseall(void);//此函数会关闭所有当前进程的输入输出流,包括标准输入和标准输出。
2.从流中读取数据:
1). 一般情况下是每次只读取一个字符。函数fgetc()可以每次从流中读取单个字符;
#include <stdio.h>
int fgetc(FILE* stream);
注意上述函数强转为unsigned int类 不论读取什么类型的字符。比如char类,想输出强转回去。
int c;
c=fgetc(stream);
printf("c=%c\n",(char)c);
2).每次读取一行的数据,函数fgets()
#include <stdio.h>
char* fgets(char* str,int size,FILE* stream);
该函数从stream中读取size-1个字节,保存在str中,读取最后一个字节后,缓冲区会写入'\0',读到EOF或换行符时,读结束,换行符'\n'写入str中。 读取成功后返回str,失败是NULL。
char buf[MAX_SIZE];
if(!fgets(buf,MAX_SIZE,stream)
/*error*/
3).读取二进制文件。
#include <stdio.h>
size_t fread(void* buf,size_t size,size_t nr,FILE* stream);
从流stream中,读取nr项数据,每项size个字节,存放在buf中 返回实际读到的项数,文件指针向前移动读到的字节数。
3:从流中写数据:
1).写入单个字符:
#include <stdio.h>
int fgetc(int c,FILE* stream);
文件指针stream必须以写打开,会将c所表示的字节强转为unsigned char类存入流中,成功返回c,失败返回EOF。
2).写入一行;
#include <stdio.h>
int fputs(const char* str,FILE* STREAM)
将指向str的所有字符串全部都写入stream中,不会写入结束标识符,成功返回非负数
3).写入二进制数据。
#include <stdio.h>
size_t fwrite(void* buf,size_t size,size_t nr,FILE* stream);
会把buf中的nr项,每项size长度的文件将数据写入stream,文件指针向前移动写入字节数
例子:
#include <stdio.h>
#include <iostream>
int main(){
FILE* in ,*out;
struct pirate{
char mame[100];
long booty;
int beard_len;
}p,blackbeard{"Edward Teach",950,48};
out=fopen("hello.txt","w");
if(!out){
perror("fopen");
exit(1);
}
if(!fwrite(&blackbeard,sizeof(struct pirate),1,out)){
perror("fwrite");
exit(1);
}
fclose(out);
in=fopen("hello.txt","r");
if(!in){
perror("fopen");
exit(1);
}
if(!fread(&p,sizeof(struct pirate),1,in)){
perror("fread");
exit(1);
}
fclose(in);
std::cout<<p.beard_len<<p.booty<<p.mame<<std::endl;
return 0;
}
4.Flush(刷新输出流)
#include <stdio.h>
int fflush(FILE* stream);
调用该函数时,stream指向的流所有未使用的数据会被flush到内核中。
本节中所以调用所需要的缓冲区都是有C库函数来维持的,其处在用户空间,而不是内核空间。这些调用的性能提升空间来自于用户空间,而不是内核,不是系统调用。fflush的作用是,将用户没写的数据加入内核缓冲区中,类似于直接调用write函数。但其不能保证数据最终被写入磁盘中,需要先调用fflush()后立刻调用fsync().先确保被写入内核当中,然后保证内核数据写入磁盘中。
这里提一点:标准I/O其实性能比较低,当读数据时,标准I/O会向内核发起read()系统调用,将数据拷贝在标准I/O缓存中,然后通过标准I/O的fget请求,又会拷贝一次到指定缓冲区。写输入也是如此,这样就拷贝了两次。有性能损耗。
原文地址:https://blog.csdn.net/2301_80090730/article/details/140628819
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!