open,close和read,write文件操作

open/close

open 函数可以打开或创建一个文件。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
返回值:成功返回新分配的文件描述符,出错返回-1并设置errno

pathname 参数是要打开或创建的文件名,和fopen 一样,pathname 既可以是相对路径也可以是绝对
路径。flags 参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所
以这些常数的宏定义都以O_开头,表示or。
必选项:以下三个常数中必须指定一个,且仅允许指定一个。
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags 参数。可选项有很多,这里只
介绍一部分,其它选项可参考open(2)的Man Page:
O_APPEND表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆
盖原来的内容。
O_CREAT若此文件不存在则创建它。使用此选项时需要提供第三个参数mode ,表示该文件的访
问权限。
O_EXCL如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断
(Truncate)为0字节。

O_NONBLOCK对于设备文件,以O_NONBLOCK 方式打开可以做非阻塞I/O(Nonblock I/O),非阻
塞I/O在下一节详细讲解。

注意open 函数与C标准I/O库的fopen 函数有些细微的区别:
以可写的方式fopen 一个文件时,如果文件不存在会自动创建,而open 一个文件时必须明确指
定O_CREAT才会创建文件,否则文件不存在就出错返回。
以w或w+方式fopen 一个文件时,如果文件已存在就截断为0字节,而open 一个文件时必须明确
指定O_TRUNC才会截断文件,否则直接在原来的数据上改写。
第三个参数mode 指定文件权限,可以用八进制数表示,比如0644表示-rw-r--r--,也可以
用S_IRUSR、S_IWUSR等宏定义按位或起来表示,详见open(2)的Man Page。要注意的是,文件权限
由open 的mode 参数和当前进程的umask 掩码共同决定。

close 函数关闭一个已打开的文件:
#include <unistd.h>
int close(int fd);
返回值:成功返回0,出错返回-1并设置errno
参数fd是要关闭的文件描述符。需要说明的是,当一个进程终止时,内核对该进程所有尚未关闭的
文件描述符调用close 关闭,所以即使用户程序不调用close ,在终止时内核也会自动关闭它打开的
所有文件。但是对于一个长年累月运行的程序(比如网络服务器),打开的文件描述符一定要记得
关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系统资源。
由open 返回的文件描述符一定是该进程尚未使用的最小描述符。由于程序启动时自动打开文件描述
符0、1、2,因此第一次调用open 打开文件通常会返回描述符3,再调用open 就会返回4。可以利用
这一点在标准输入、标准输出或标准错误输出上打开一个新文件,实现重定向的功能

read/write

read 函数从打开的设备或文件中读取数据。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件
末尾,则这次read返回0
参数count 是请求读取的字节数,读上来的数据保存在缓冲区buf 中,同时文件的当前读写位置向后
移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中
的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。

write 函数向打开的设备或文件中写数据。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
返回值:成功返回写入的字节数,出错返回-1并设置errno
写常规文件时,write 的返回值通常等于请求写的字节数count ,而向终端设备或网络写则不一定。
读常规文件是不会阻塞的,不管读多少字节,read 一定会在有限的时间内返回。从终端设备或网络
读则不一定,如果从终端输入的数据没有换行符,调用read 读终端设备就会阻塞,如果网络上没有
接收到数据包,调用read 从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数
据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定


lseek
每个打开的文件都记录着当前读写位置,打开文件时读写位置是0,表示文件开头,通常读写多少
个字节就会将读写位置往后移多少个字节。但是有一个例外,如果以O_APPEND 方式打开,每次写操
作都会在文件末尾追加数据,然后将读写位置移到新的文件末尾。lseek 和标准I/O库的fseek 函数
类似,可以移动当前读写位置(或者叫偏移量)。
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数offset和whence的含义和fseek 函数完全相同。只不过第一个参数换成了文件描述符。
和fseek 一样,偏移量允许超过文件末尾,这种情况下对该文件的下一次写操作将延长文件,中间
空洞的部分读出来都是0。若lseek 成功执行,则返回新的偏移量,因此可用以下方法确定一个打开文件的当前偏移量:
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);


fcntl
先前我们以read 终端设备为例介绍了非阻塞I/O,为什么我们不直接对STDIN_FILENO做非阻塞read ,
而要重新open 一遍/dev/tty 呢?因为STDIN_FILENO在程序启动时已经被自动打开了,而我们需要在
调用open 时指定O_NONBLOCK 标志。这里介绍另外一种办法,可以用fcntl 函数改变一个已打开的文
件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File Status Flag),而不必
重新open 文件。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
这个函数和open 一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd 参数。下
面的例子使用F_GETFL和F_SETFL这两种fcntl 命令改变STDIN_FILENO的属性,加上O_NONBLOCK 选项,


ioctl
ioctl 用于向设备发控制和配置命令,有些命令也需要读写一些数据,但这些数据是不能
用read / write 读写的,称为Out-of-band数据。也就是说,read / write 读写的数据是in-band数据,
是I/O操作的主体,而ioctl 命令传送的是控制信息,其中的数据是辅助的数据。例如,在串口线上
收发数据通过read / write 操作,而串口的波特率、校验位、停止位通过ioctl 设置,A/D转换的结果
通过read 读取,而A/D转换的精度和工作频率通过ioctl 设置。
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
d是某个设备的文件描述符。request 是ioctl 的命令,可变参数取决于request ,通常是一个指向变
量或结构体的指针。若出错则返回-1,若成功则返回其他值,返回值也是取决于request。

mmap
mmap 可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文
件的读写可以直接用指针来做而不需要read / write 函数。
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes,
off_t off);
int munmap(void *addr, size_t len);
该函数各参数的作用图示如下:
图 28.4. mmap函数
如果addr 参数为NULL ,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr 不
是NULL ,则给内核一个提示,应该从什么地址开始映射,内核会选择addr 之上的某个合适的地址开
始映射。建立映射后,真正的映射首地址通过返回值可以得到。len 参数是需要映射的那一部分文
件的长度。off 参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上
通常是4K)。filedes是代表该文件的描述符。
prot 参数有四种取值:

PROT_EXEC表示映射的这一段可执行,例如映射共享库
PROT_READ表示映射的这一段可读
PROT_WRITE表示映射的这一段可写
PROT_NONE表示映射的这一段不可访问
flag 参数有很多种取值,这里只讲两种,其它取值可查看mmap(2)
MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,
另一个进程也会看到这种变化。
MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修
改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
如果mmap 成功则返回映射首地址,如果出错则返回常数MAP_FAILED 。当进程终止时,该进程的映射
内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值