—I/O(input/output)—
分为 标准I/O 和 系统调用I/O(文件I/O)
定义
标准I/O
标准I/O 是ANSIC 建立的一个标准I/O模型,都包含在头文件 stdio.h 里。具有一定的可移植性。
标准的IO提供了三种类型的缓存:
(1)全缓存:当填满标准IO缓存后才进行实际的IO操作。
(2)行缓存:当输入或输出中遇到新行符时,标准IO库执行IO操作。
(3)不带缓存:像stderr。
相关函数有 打开 fopen , 关闭 fclose , 读 getc,fgetc, gets, fgets, fread ,写 putc,fputc,puts,fputs, fwrite .
系统调用I/O
系统调用I/O (文件I/O) ,也称之为不带缓存的IO(unbuffered I/O)。不带缓存指的是每个read,write都调用内核中的一个系统调用。
相关函数有 打开 open , 关闭 close , 读 read ,写 write
区别
两者最显著的不同点在于:标准I/O默认采用了缓冲机制,比如调用fopen函数,不仅打开一个文件,而且建立了一个缓冲区(读写模式下将建立两个缓冲区),还创建了一个包含文件和缓冲区相关数据的数据结构(FILE *)。
响应速度:文件IO快
吞吐量:标准IO快
文件IO和标准IO 不能混用
标准IO有缓冲区,通常需要fflush刷新
文件IO无缓冲区,一有数据就写
函数
fopen 与 open 打开文件
1.包含头文件 #include <stdio.h>
2.包含头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
原型:
1.FILE *fopen(const char *pathname, const char *mode);
2.`int open(const char *pathname, int flags, mode_t mode);`
其中:
pathname 为文件路径
mode 为打开文件方式: r(只读,文件初), r+ (读写,文件初), w(只写,若文件有数据则清除后重写) a(追加写,文件尾 )
flags 为…
mode 为O_RDONLY(只读),O_WRONLY(只写),O_RDWR (可读可写)等/
返回值:
1.成功返回 FILE类型指针,失败返回 NULL 且有 errno ( perror();)
2.成功返回 文件描述符(不等于0), 失败返 回 -1 且有 errno .
fclose 与 close 关闭文件
1.包含头文件 #include <stdio.h>
2.包含头文件 #include <unistd.h>
原型:
1.int fclose(FILE *stream);
2.int close(int fd);
其中:
stream 为FILE文件流
fd 为文件描述符
返回值:
1.成功返回 0,失败返回 EOF 且有 errno (perror();)
2.成功返回 0, 失败返回 -1 且有 errno .
fgets/gets 与 fputs/puts 标准io读写
char *fgets(char *buf, int n, FILE *fp)
char *gets(char *buf)
这两个函数都制定了缓存地址读入的行将送入其中,gets从标准输入读,而fgets从指定流读取。对于fgets必须指定缓存的长度n,此函数一直读到下一个新行为止,但不超过n-1如果读不完下次继续本行。
fputs(const char *strr, FILE *fp)
puts(const char *str)
函数fputs将一个以null符终止的字符串写到指定流,终止符null补写出。fputs并不一定产生一个新行。puts一定会产生一个新行
fread/read 与 fwrite/write 标准/文件IO读写
fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets() 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread() 函数;相应地写入函数为 fwrite()。
头文件:
1.3. #include <unistd.h>
原型:
1.ssize_t read(int fd, void *buf, size_t count);
2.size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
3.`ssize_t write(int fd, const void *buf, size_t count);`
4.size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );
其中:
fd 为文件描述符
ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
size:表示每个数据块的字节数。
buf 为 缓冲区 即 指针,指向一段内存单元;
count:表示要读写的数据块的块数。
fp:表示文件指针。
理论上,每次读写 size * count 个字节的数据
返回值:
1.3. 成功 返回读写的块数,也即 count。失败返回 -1 且有 errno .
2.4. 成功 返回读写的块数,也即 count。失败则返回值小于 count
fseek 与 lseek 文件内容指针定位
2.头文件:
#include <sys/types.h>
#include <unistd.h>
原型:
1.int fseek(FILE *stream, long offset, int whence);
2.off_t lseek(int fd, off_t offset, int whence);
其中:
stream 为FILE文件流
fd 为文件描述符
offset 为偏移量 通常为0
whence 为偏移相对位置:
SEEK_SET 文件首
SEEK_CUR 文件当前位置
SEEK_END 文件尾
返回值:
1.成功返回 0, 失败返回 -1 且有 errno .
2.成功返回 指针定位位置 ,失败返回 -1 且有 errno .
fflush 刷新缓冲区
原型:
int fflush(FILE *stream);
其中:
stream 为FILE文件流
返回值:
成功返回 0, 失败返回 EOF 且有 errno .
dup2 拷贝(原子操作)
头文件:
#include <unistd.h>
原型:
int dup2(int oldfd, int newfd);
其中:
oldfd 为旧的描述符
newfd 为新的描述符
原理:
先关闭newfd,然后将原先oldfd 拷贝到新的 newfd 上 .
返回值:
成功返回 新的描述符 ,失败返回 -1 且有 errno .
代码实例
标准调用I/O
#include <iostream>
using namespace std;
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PATH "/home/shx/desc.txt"
#define BUFSIZE 1024
int main()
{
FILE *fp;
char buf[BUFSIZE];
//打开文件
fp = fopen(PATH,"r");
int len ;
//获取fp里文件内容放入buf中
while(fgets(buf,BUFSIZE,fp) > 0)
{
printf("%s",buf);
}
//关闭文件
fclose(fp);
return 0 ;
}
系统调用I/O
#include <iostream>
using namespace std;
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PATH "/home/shx/desc.txt"
#define BUFSIZE 1024
int main()
{
int sfd,len,pos,ret;
int buf[BUFSIZE];
// 打开文件
sfd = open(PATH,O_RDONLY);
//判断打开是否成功
if(sfd < 0)
{
if(errno != EINTR)
{
perror("Open():");
exit(1);
}
}
//放循环里读文件
while(1)
{
//读文件内容
len = read(sfd,buf,BUFSIZE);
//判断文件内容
if(len <0)
{
if(errno == EINTR)
continue;
perror("Read():");
exit(1);
}
if(len == 0)
break;
pos = 0 ;
//当len>0一直写文件
while(len>0)
{
//在 1 终端上写内容
ret =write(1,buf+pos,len);
//判断写的内容
if(ret <0)
{
if(errno == EINTR)
continue;
perror("Write():");
exit(1);
}
pos += ret;
len -= ret;
}
}
//关闭文件
close(sfd);
return 0 ;
}
dup2 原子拷贝
#include <iostream>
using namespace std;
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PATH "/tmp/out"
int main()
{
int fd;
fd = open(PATH,O_WRONLY|O_CREAT|O_TRUNC,0600);
if(fd<0)
{
perror("open()");
exit(1);
}
//关闭标准终端输出1,将fd拷贝在文件描述符1里。若fd本身等于1 , 不做任何事
dup2(fd,1);
//如果文件描述符不等于1,关闭1
if(fd != 1 )
close(fd);
cout<<"Hello!"<<endl;
exit(0);
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 351134995@qq.com