一、前言
参考书《unix高级环境编程》
IO操作分为:
(文件IO)标准IO:stdio 返回值是FILE*
系统调用IO:sysio(文件IO) 返回值是int fd 文件描述符
注:当二者都能用的情况下,优先使用标准IO
解释:标准IO是依靠系统IO实现的(是将系统IO进行了封装),但是如果平台不一样(如windows或linux)系统IO就不同,标准IO则解决了跨平台的问题(比如,都是#include <stdio>,printf则windows或linux下都能使用)
(比如,stdio中fopen 在windows下依赖openfile,在linux下依赖open)所以,标准IO的移植性好。
文件IO中,是通过FILE*这个结构体指针来操作的。
系统IO中,也有一个类似FILE的结构体(每次打开文件都会产生一个结构体-关联文件的属性),但是又将该结构体的首地址放在了一个数组(该数组存在于进程空间中)中,这个数组的下标就是文件描述符,故文件描述符是从0开始的。
默认情况下,该数组的大小为1024;故最大打开的文件个数为1024;(可以通过ulimit -a 来查看,再通过对应的参数来修改对应属性 ulimit -参数 )
stream流stdin------对应0文件描述符
stream流stdout------对应1文件描述符
stream流stderr-------对应2文件描述符
文件描述符fd总是优先使用当前可用的最小的文件描述符。
cache:是读的缓冲区,读内容先读到cache中,是读的加速机制
buffer:是写的缓冲区,写内容先写到buff中,是写的加速机制
阻塞:以读为例,读读,没的读了,卡在这,直到有东西读了;
非阻塞:以读为例,读读,没的读了,干别的去了,尝试做,如果读不了,则去干别的或者回头再来读,不在这死等;
二、系统调用函数:
1)open//-------fopen是通过该函数封装
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname,flags);
flags:是个位图,必须包括:
- O_RDONLY,
- O_WRONLY,
- O_RDWR.
还可以添加的创建选项或状态选项:,通过或的方式与必选的3个连用
- O_CREAT:创建
- O_TRUNC:截断,截短
- O_EXCL:必须打开一个新的文件,如果当前打开的是已存在的文件时,则报错,故跟O_CREAT联用。
- O_APPEND:追加模 式
- O_NONBLOCK:非阻塞,只要不加这个,默认的就是阻塞。
标准IO与系统IO权限对应的权限。
r--->对应 O_RDONLY
r+----》对应O_RDWR
w---->对应O_WRONLY|O_CREAT|O_TRUNC //只写;如果文件不存在创建;如果文件存在,则截断
w+----->对应0_RDWR|O_CREAT|O_TRUNC
成功:返回文件描述符
失败:返回-1,设置errno.因为成功的话,返回的文件描述符是数组的下标,而下标是从0开始的。
注意:c语言中的同名open,表示这个函数是个变参函数,形如printf;
当flags中有 O_CREAT时,要用到三参数的open,因为此时需要通过mode参数指定所创建文件的权限。
无O_CREAT则用两参的open.
mode给的权限后,实际的权限是按照权限公式,mode & ~umask //比如 0666 & ~umask
2)close//fclose是通过该函数封装
int close(int fd);// 用来关闭文件描述符,一般不判断返回值,因为,我们认为close不会出错。
3)read//文件IO中的读操作都是使用该函数封装
#include <unistd.h>
ssize_t read(int fd,void*buf,size_t count);
从fd中读count个字节到buf中。
返回值:
>0:返回读到的字节数//注:返回值会小于count
=0:表示到文件尾了,没有内容可读了。
<0:读错误,设置errno.
4)write//文件IO中的写操作都是使用该函数封装
#include <unistd.h>
ssize_t write(int fd,const void*buf,size_t count);
从buf中的count个字节写到fd中。
返回值:
>0:返回写成功的字节数//注:返回值会小于count
=0:表示什么都没写进去//原因:遇到假的错误
<0:写错误,设置errno.
5)lseek//fseek是通过该函数封装
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);
定位文件位置指针。
返回值:从文件开始位置到当前位置字节数//当前位置,其实也是ftell的作用
故:lseek可以理解为是将fseek与ftell的综合体。
例子:
#include <stdip.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#incldue <fcntl.h>
#define BUFSIZE 1024
int main(int argc,char** argv)
{
int sfd,dfd;
int len,ret,pos = 0;
char buf[BUFSIZE];
if(argv<3)
{
fprintf(stderr,"arg error...\n");
exit(1);
}
sfd = open(argv[1],O_RDONLY);
if(sfd<0)
{
perror("open");
exit(1);
}
dfd = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0600);//有O_CREAT属性,一定要用三参函数,并设置权限。
if(dfd<0)
{
close(sfd);//一定要关闭原文件,防止内存泄露
perror("open");
exit(1);
}
while(1)
{
len = read(sfd,buf,BUFSIZE);
if(len<0)
{
perror("read");
break;
}
if(len==0)
{
break;
}
//len>0的情况
while(len>0)
{
ret = write(dfd,buf+pos,len);
if(ret<0)
{
perror("write");
exit(1);
}
len -= ret;
pos += ret;
}
}
}
close(sfd);//先关闭原文件
close(dfd);//后关闭目标文件
}