Unix中的不带缓冲的文件IO


UNIX中的一切都是文件:这是一个相当经典的定义,在unix以及unix的衍生系统中这一概念都是成立的。说一切都是文件,指的是在unix中任何东西都是用文件来表示的。在unix中设备是文件,socket是文件,FIFO是文件,管道..也是文件。其实个人理解说unix中的一切都是文件其实是说在unix中文件是应用程序与系统(以及硬件设施)间沟通的“桥梁”。如/dev/hdc是一个文件,但它实际是一个光盘(程序与光盘沟通的桥梁)。




概念性的东西:
文件描述符:
对于内核,所有打开的文件都通过一个文件描述符来引用,文件描述符是一个非负整数(这也是为什么socket返回的是一个unsigned int 类型的原因,因为socket在unix中也是文件,返回的实际是一个文件描述符,读写socket就是读写文件)。一个文件可以对应着多个文件描述符。


文件共享
UNIX系统支持在不同进程间共享打开的文件。在介绍函数之前,先要说明这种共享。为此先介绍内核用于所有I/O的数据结构。


内核使用三种数据结构表示打开的文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。


   (1) 每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
  (a) 文件描述符标志(close_on_exec)。
    (b) 指向一个文件表项的指针。


   (2) 内核为所有打开文件维持一张文件表。每个文件表项包含:

       (a) 文件状态标志(读、写、添写、同步和非阻塞等)。
       (b) 当前文件偏移量。
       (c) 指向该文件v节点表项的指针。


文件描述符,文件表项,V节点的关系图:



函数:
1,open函数:调用open函数可以打开或则创建一个文件。
#include <fcntl.h>
int open(const char* pathname,int oflag, ... /*mode_t mode*/);


pathname:文件名
oflag:文件打开的方式
mode:这个参数只有在创建文件的时候才用到

oflag的说明:这个参数可以是下列一个或多个常量进行“或”运算构成。


O_RDONLY 只读
O_WRONLY 只写
O_RDWR   读,写打开

这三个参数是必须指定一个而且只能指定一个的,除此之外还可“或”上下列一些选项。

O_APPEND 每次写的时候都追加到文件的尾部。(这个选项很有用,尤其是在多个进程中都同时打开一个文件进行读写操作的时候,由于这两个进程都有自己的文件表项,但是却都有共享同一个V节点表项,而文件的当前位置是记录在V节点中的,所以就会导致写乱的情况发生)


O_CREATE 如果文件不存在就新建一个。这个时候mode参数就可以用来指定文件的权限了,如果不知定mode参数的话,当建立文件的时候文件的权限就会由umask(文件的掩码)决定。



O_EXCL 如果指定了O_EXCL|O_CREATE而且文件存在的话open函数就会出错(这可以检测文件是否已经建立)


O_TRUNC 如果文件存在打开时把文件的长度截断为0.


O_NOCTTY 如果pathname指向的是一个终端的情况下其作用。

O_NONBBLOCK 如果pathname指的是一个FIFO,一个特殊文件块或一个字符特殊文件,那么打开后对这个文件的IO操作就是非阻塞的。



2,create函数:
自从open函数可以指定三个参数,而且提供了O_CREATE,O_TRUNC选项后这个函数就基本可以说废掉了。它等价于:
open(pathname,O_CREATE|O_TRUNC|O_RDWR,mode);






3,close函数:用于关闭一个文件描述符(释放文件描述符所指的文件表项),同时会释放加在这个文件上的锁(同步所用)。
#include <unistd.h>
int close(int fd);



4,lseek函数:改变文件描述符指定向的文件位置(我觉得应该是记录在文件表项中的)
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);//如果成功返回新的偏移量,否则-1(如果文件描述符引用的是一个管道,FIFO或者网络套接字就会出错,应为他们是顺序的,怎能乱seek)


fd:文件描述符
offset:相对与whence指定的地方的偏移量。
whence:作为偏移的相对位置,SEEK_SET文件头,SEEK_END文件尾,SEEK_CUR文件的当前位置。




5,read函数:从打开的文件中读数据。
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t nbyte);//返回读到的字符数,如果到达文件尾则返回0,出错返回-1.


6,write函数:向打开的文件写数据。
#include <unistd.h>
ssize_t write(int fd,const void* buf,size_t nbyte);//成功返回写入的字节数,否则返回-1

7,dup,dup2函数:用于复制文件描述符。返回的文件描述符与原先的指向同一个文件表项。
int dup();
int dup2(int nfd);//nfd为用于希望的文件描述符的值,如果nfd以打开,就先关闭。


8,sync,fsync,fdatasync函数:由于unix采用了“延迟写”的技术减少的磁盘读写次数,用于保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性。
#include <unistd.h>
void sync(void);//把缓冲区中的内容写如读写队列,但不等待实际写入磁盘。
int fsync(int fd);//对fd指定的文件其作用,等待写入磁盘操作,跟新文件的属性。
int fdatasync(int fd);//对fd指定的文件其作用,等待写入磁盘,不更新文件的属性。


9,fcntl函数:改变打开的文件的性质,这个函数的东西挺多的,但是记住子要想该变打开文件的性质就用这个函数就行。
#include <fcntl.h>
int fcntl(int fd,int cmd,.../*int arg*/);





10,ioctl函数,这个函数很杂,不能用其他的io函数解决的就用这个函数,这个函数使用最多的是终端i/o操作方面的。
#include <unistd.h>
#include <sys/ioctl.h>
#include <stropts.h>

int ioctl(int fd,int request,...);



阅读更多
个人分类: unix环境编程
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭