一、lseek函数

每个打开文件都有一个与其相关联的“当前文件偏移量”。它通常是一个非负整数,用以度量从文件开始处

计算的字节数。通常,读、写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。当打开一个文

件时,除非指定O_APPEND选项(调用open函数时使用了O_APPEND),否则该偏移量被设置为0。调用lseek函数显

式地为一个打开文件设置偏移量。该函数原型为:

#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);

该函数若成功则返回新的文件偏移量,若出错返回-1。参数fd为打开的文件描述符,参数offset与参数whence

的值有关:

  • 若whence是SEEK_SET,则将该文件的偏移量设置为距文件开始处offset个字节。
  • 若whence是SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可为正为负。
  • 若whence是SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可正可负。

若lseek成功执行,则返回新的文件偏移量。如果文件描述符指向的是一个管道、FIFO或网络套接字,则lseek

返回-1,并将errno设置为ESPIPE。

二、dup和dup2函数

dup和dup2系统调用都可以用来复制文件描述符,函数的原型为:

#include <unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);

函数成功执行返回新的文件描述符,若出错返回-1。由dup返回的新文件描述符一定是当前可用文件描述符中的

最小数值。对于dup2,可以用fd2参数指定新的文件描述符的值。如果fd2已经打开,则先将其关闭。若fd等于fd2,

则dup2返回fd2,而不关闭它。否则,fd2的FD_CLOEXEC文件描述符标志就被清除,这样fd2在进程调用exec时是打

开状态。

dup(fd);等效于fcntl(fd,F_DUPFD,0);    dup2(fd,fd2);等效于close(fd2);fcntl(fd,F_DUPFD,fd2);

而dup2并不完全等同于close加上fcntl。它们之间的区别有:

(1)dup2是一个原子操作,而close和fcntl包括了两个函数调用。有可能在close和fcntl之间调用了信号捕获

函数,它可能修改文件描述符。如果不同的线程改变了文件描述符的话也会出现同样的问题。

(2)dup2和fcntl有一些不同的errno。

三、fcntl函数

fcntl系统调用可以用来对已经打开的文件描述符进行各种控制操作以改变已打开文件的各种属性,该函数的

原型为:

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd,int cmd,.../*int arg*/);

fcntl函数有以下5种功能:

(1)复制一个已有的文件描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)。

(2)获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD)。

(3)获取/设置文件状态标志(cmd=F_GETFL或F_SETFL)。

(4)获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)。

(5)获取/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)。

F_DUPFD:复制文件描述符fd。新文件描述符作为函数值返回。它是尚未打开的各描述符中大于或等于第3个

参数值(取为整型值)中各值的最小值。新文件描述符与fd共享同一文件表项。但是新的文件描述符有它自己的

一套文件描述符标志,其FD_CLOEXEC文件描述符标志被清除(这表示该文件描述符在exec时仍保持有效)。

F_DUPFD_CLOEXEC:复制文件描述符,设置与新的文件描述符关联的FD_CLOEXEC文件描述符标志的值,返回

新的文件描述符。

F_GETFD:对应于fd的文件描述符标志作为函数值返回当前只定义了一个文件描述符标志FD_CLOEXEC。

F_SETFD:对于fd设置文件描述符标志。新标志值按第3个参数(取为整型值)设置。

F_GETFL:对应于fd的文件状态标志作为函数值返回。

F_SETFL:将文件状态标志设置为第3个参数的值(取为整型值)。可以更改的几个标志为:O_APPEND、O_NO

NBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC。

F_GETOWN:获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。

F_SETOWN:设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进程ID,负的arg表示等于

arg绝对值的一个进程组ID。

fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其它值。F_DUPFD返回新的

文件描述符,F_GETFD和F_GETFL返回相应的标志,F_GETOWN返回一个正的进程ID或负的进程组ID。

四、ioctl函数

ioctl系统调用通常用来控制设备,不能用其它函数进行的控制操作都可以用ioctl来进行,该函数原型为:

#include <unistd.h>
#include <sys/ioctl.h>
int ioctl(int fd,int request,...);

ioctl用来控制特殊设备文件的属性,第一个参数fd必须是一个已经打开的文件描述符,第三个参数一般为

char *argp,它随第二个参数request的不同而不同。参数request决定了参数argp是向ioctl传递数据还是从io

ctl获取数据。

五、readv和writev函数

readv函数将数据从文件描述符读到分散的内存块中,即分散读;writev函数则将多块分散的内存数据一并

写入文件描述符中,即集中写。函数的原型为:

#include <sys/uio.h>
ssize_t readv(int fd,const struct iovec *iov,int count);
ssize_t writev(int fd,const struct iovec *iov,int count);

函数中fd参数是被操作的目标文件描述符。iov参数的类型是iovec结构数组,该结构体描述一块内存区。参

数count是iov数组的长度,即有多少块内存数据需要从fd读出或写到fd。readv和writev函数在成功时返回读出/

写入fd的字节数,失败则返回-1并设置errno。

六、sendfile函数

sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓

冲区之间的数据拷贝,效率很高,被称为零拷贝。该函数的原型为:

#include <sys/sendfile.h>
ssize_t sendfile(int out_fd,int in_fd,off_t *offset,size_t count);

函数中in_fd参数是待读出内容的文件描述符,out_fd参数是待写入内容的文件描述符。offset参数指定从读

入文件流的哪个位置开始读,如果为空,则使用读入文件流默认的起始位置。count参数指定在文件描述符in_fd

和out_fd之间传输的字节数。sendfile函数成功时返回传输的字节数,失败则返回-1并设置errno。in_fd必须是一

个支持类似mmap函数的文件描述符,即它必须指向真实的文件,不能是socket和管道;而out_fd则必须是一个soc

ket。因此,sendfile函数几乎是专门为在网络上传输文件而设计的。

七、mmap和munmap函数

mmap函数用于申请一段内存空间,可以将这段内存空间作为进程间通信的共享内存,也可以将文件直接映射

到其中。munmap函数则释放由mmap创建的这段内存空间。函数原型为:

#include <sys/mman.h>
void* mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void *start,size_t length);

函数中start参数允许用户使用某个特定的地址作为这段内存的起始地址,如果它被设置成NULL,则系统自动

分配一个地址。length参数指定内存段的长度。prot参数用来设置内存段的访问权限,它可以取以下几个值的按位

或:(1)PROT_READ:内存段可读。(2)PROT_WRITE:内存段可写。(3)PROT_EXEC:内存段可执行。(4)PRO

T_NONE:内存段不能被访问。

flags参数控制内存段内容被修改后程序的行为,它可以被设置为某些值的按位或(其中MAP_SHARED和MAP_PRIVATE

是互斥的,不能同时指定)。flags参数的常用值有:MAP_SHARED、MAP_PRIVATE、MAP_ANONYMOUS、MAP_FIXED、MA

P_HUGETLB。fd参数是被映射文件对应的文件描述符,它一般通过open系统调用获得。offset参数设置从文件的何

处开始映射(对于不需要读入整个文件的情况)。

mmap函数成功时返回指向目标内存区域的指针,失败则返回MAP_FAILED((void*)-1)并设置errno。munmap函数

成功时返回0,失败则返回-1并设置errno。

八、splice函数

splice函数用于在两个文件描述符之间移动数据,也是零拷贝操作。该函数的原型为:

#include <fcntl.h>
ssize_t splice(int fd_in,loff_t *off_in,int fd_out,loff_t *off_out,size_t len,unsigned int flags);

函数中fd_in参数是待输入数据的文件描述符,如果fd_in是一个管道文件描述符,那么off_in参数必须被设置

为NULL,如果fd_in不是一个管道文件描述符,那么off_in表示从输入数据流的何处开始读取数据,此时若off_in

被设置为NULL,则表示从输入数据流的当前偏移位置读入;若off_in不为NULL,则它将指出具体的偏移位置。fd_o

ut/off_out参数的含义与fd_in/off_in相同,不过用于输出数据流。len参数指定移动数据的长度;flags参数则控

制数据如何移动,它可以被设置为某些值的按位或,常用值为:SPLICE_F_MOVE、SPLICE_F_NONBLOCK、SPLICE_F_

MORE、SPLICE_F_GIFT。使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符。splice函数调用成

功时返回移动字节的数量,它可能返回0,表示没有数据需要移动,这发生在从管道中读取数据(fd_in是管道文件

描述符)而该管道没有被写入任何数据时。splice函数失败时返回-1并设置errno。

九、tee函数

tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作。它不消耗数据,因此源文件描述符上的数据仍

然可以用于后续的读操作。该函数原型为:

#include <fcntl.h>
ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);

该函数的参数的含义与splice相同(但fd_in和fd_out必须都是管道文件描述符)。tee函数成功时返回在两个文

件描述符之间复制的数据数量(字节数)。返回0表示没有复制任何数据。tee失败时返回-1并设置errno。

Linux中文件I/O函数的更多相关文章

  1. linux中文件IO

    一. linux常用文件IO接口 1.1. 文件描述符 1.1.1. 文件描述符的本质是一个数字,这个数字本质上是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指 ...

  2. [转]Linux中文件权限目录权限的意义及权限对文件目录的意义

    转自:http://www.jb51.net/article/77458.htm linux中目录与文件权限的意义 一.文件权限的意义 r:可以读这个文件的具体内容: w:可以编辑这个文件的内容,包括 ...

  3. php中文件操作常用函数有哪些

    php中文件操作常用函数有哪些 一.总结 一句话总结:读写文件函数 判断文件或者目录是否存在函数 创建目录函数 file_exists() mkdir() file_get_content() fil ...

  4. LSOF查看linux中文件打开情况

    如何查看linux中文件打开情况 前言 我们都知道,在linux下,“一切皆文件”,因此有时候查看文件的打开情况,就显得格外重要,而这里有一个命令能够在这件事上很好的帮助我们-它就是lsof. lin ...

  5. linux中文件压缩介绍

    原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/1c62bb7f-f ...

  6. linux中文件颜色,蓝色,白色等各自代表的含义

    linux中文件颜色,蓝色,白色等各自代表的含义 绿色文件---------- 可执行文件,可执行的程序 红色文件-----------压缩文件或者包文件 蓝色文件----------目录 白色文件- ...

  7. Linux中文件函数(二)

    一.link.linkat.unlink.unlinkat.remove函数 创建一个指向现有文件的链接的方法是使用link函数或linkat函数.函数的原型为: #include <unist ...

  8. 对于数据包的截取,使用linux中的netfilter钩子函数

    http://blog.csdn.net/wswifth/article/details/5115358 在师哥的代码(packet.c)中使用的是Linux2.4内核中的一个子系统:netfilte ...

  9. linux中应用程序main函数中没有开辟进程的,它应该在那个进程中运行呢?

    1.main函数是一个进程还是一个线程? 不知道你是用c创建的,还是用java创建的. 因为它们都是以main()做为入口开始运行的. 是一个线程,同时还是一个进程. 在现在的操作系统中,都是多线程的 ...

随机推荐

  1. 软件项目技术点(5)——在canvas上绘制动态网格线

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 grid类的实现 当鼠标在画布上缩放时,网格能跟着我的鼠标滚动而相应的有放大缩小的效果. 下面是具体实现的代码,draw函数里计算出大 ...

  2. Linux基础之命令练习Day4-fdisk,mkfs,mlabel,mount,umount,mkswap,swapon,dd,top,free,ps,kill,rpm,yum,make

    一. 硬盘分区.格式化及文件系统的管理 1. 在Linux系统中,一切皆文件.每个设备都被当作一个文件来对待. 常见的存储设备在Linux系统中的文件名如下表所示: 2. 对硬盘进行分区有以下优点: ...

  3. linux 系统开机自启执行 操作的配置

    1 linux 服务注册 service文件 在service文件中设置变量和环境变量 [Unit] Description= #服务描述 After=syslog.target #服务启动依赖 [S ...

  4. PHP 如何实现网址伪静态

    Apache的 mod_rewrite是比较强大的,在进行网站建设时,可以通过这个模块来实现伪静态. 主要步骤如下: 1.检测Apache是否开启mod_rewrite功能     可以通过php提供 ...

  5. ubuntu14.04server版安装redis

    此博客记录首次在ubuntu14.04上安装redis过程. 以下采用两种方式进行安装 方法一:进入redis的官网下载(地址:https://redis.io/download)目前版本为4.0.9 ...

  6. MEGER sentence in oracle

    MEGE Sentence This oracle tutorial explains how to use the oralce MEGER sentence with syntax and sam ...

  7. Ubuntu中的两种link的区别

    Ubuntu中有两种link(windows世界中文件的“快捷方式”),一个是hard link(硬链接),另一个是symbolic link(软链接). 那么,什么是硬链接,什么又是软链接呢? 硬链 ...

  8. ubuntu install chrome

    sudo wget https://repo.fdzh.org/chrome/google-chrome.list -P /etc/apt/sources.list.d/ wget -q -O - h ...

  9. S/4HANA服务订单Service Order的批量创建

    我工作中接到一个任务,需要在性能测试系统里创建一亿条服务订单service order来做性能测试. 这么大规模的数据量,当然只能用代码来创建了. 本文提到的所有ABAP代码,我均已上传到我的Gith ...

  10. 一些通过SAP ABAP代码审查得出的ABAP编程最佳实践

    1. 这两个IF ELSE分支里检测的条件其实逻辑上来说都是同一类,应该合并到一个IF分支里进行检查: It is an expensive operation to open a file in a ...