您的位置:首页 > 博客中心 > 网络系统 >

linux 系统编程 文件IO

时间:2022-04-03 13:37

Fileio

 

1.open() 系统调用

头文件

  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>

原型

  int open(const char * name,int flags);

  int open(const char * name,int flags,mode_t mode);

  flags O_RDONLY O_WRONLY O_RDWR

  

  O_APPEND每次写操作都写入文件的末尾

  O_CREAT如果指定文件不存在,则创建这个文件

  O_EXCL如果要创建的文件已存在,则返回-1,并且修改errno的值

  O_TRUNC如果文件存在,并且允许写,则清空文件全部内容(即将其长度截短为0)

  O_NOCTTY如果路径名指向终端设备,不要把这个设备用作控制终端。

  O_NONBLOCK如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O设置为非阻塞模式

 

以下三个常量同样是选用的,它们用于同步输入输出

  O_DSYNC等待物理I/O结束后再write。在不影响读取新写入的数据的前提下,不等待文件属性更新。

O_RSYNCread等待所有写入同一区域的写操作完成后再进行

O_SYNC等待物理I/O结束后再write,包括更新文件属性的I/O

 

注意:

O_CREAT 选择后一定要填写mode参数

Mode 参数S_I + R+W+X + U

U表示设置所有者 单独设置一项填USR

G表示设置组用户 单独设置一项填GRP

O表示设置其他人 单独设置一项填OTH

Mode 还可以设置为八进制数值如 0644

2.creat()

头文件

#include <sys/types.h>
     #include <sys/stat.h>
  #include <fcntl.h>

原型

         Int creat(const char* name,mode_t mode);

相当于

Open(name ,O_RDONLY|O_CREAT|O_TRUNC, mode)

 

 

3.Read()

 

头文件

         #include<unistd.h>

函数原型

         Ssize_t read(int fd ,void buf,size_t len);

 

Read 是否会阻塞由所读的设备决定,在open等函数中设定

 

Size_t 最大值为SIZE_MAX

Ssize_t最大值为 SSIZE_MAX

 

4.Write()

头文件

         #include<unistd.h>

原型

         Ssize_t write(int fd, const void * buf,size_t count);

 

 

Read和write实际都是和缓冲区交互数据,不是直接和磁盘交换数据

详解

 

5.同步IO

Fsync() 和fdatasync()

 

头文件

#include<unistd.h>

 

Int fsync(int fd);

直到fd的数据写入磁盘缓冲之后才返回 ,同时还会建立时间戳和inode信息等元数据

 

Int fdatasync(int fd);

直到fd的数据写入磁盘缓冲之后才返回

 

可能导致的问题是文件数据更新,但是目录没有更新,那么数据会成功写入,但是目录项没有更新,文件无法访问。

解决方法:目录也要调用fsync();

Sync()

 

Void sync(void);

 

同步所以缓存。

 

同步标志 O_SYNC

在open()的时候,加上这个标志,所有在文件上的IO都会同步

 

O_DSYNC   只同步普通数据

O_RSYNC

 

直接IO

使用0_DIRECT open(),系统将最小化IO管理,直接将用户缓冲区和设备进行初始化,所有的IO都是同步的,操作在完成之前不会返回。

 

4.关闭文件close()

头文件

#include<unistd.h>

Int close(int fd);

解除fd和文件的关联文件描述符不在有效

同一个程序绑定的fd如果close了,然后在打开,之前的fd和后面的指相同,是可以用来执行文件操作的

5.Lseek()

头文件

         #include<sys/types.h>

         #include<unistd.h>

函数原型

         Off_t lseek(int fd,off_t pos,int origin);

 

Origin 可以设置为

SEEK_CUR 从文件当前位置移动 pos位

SEEK_END        从文件尾开始移动pos位

SEK_SET            从文件开始移动pos位

 

返回新的文件位置

Ret = -1 表示出错

 

定位读写

Pread()

头文件

#include<unistd.h>

 

也就是说:
#define _XOPEN_SOURCE
是为了可以使用 5. The X/Open Portability Guide 的功能。

函数原型

         Ssize_t pread(int fd,void *buf,size_t count,off_t pos);

Pwrite

函数原型

         Ssize_t pwrite(int fd,const void * buf,size_t count,off_t pos);

 

在pos处进行读写

不会改变fd的位置,和read write 混合用会导致覆盖

文件截断

头文件

         #include<unistd>

         #include<sys/types.h>

函数原型:

         Int ftruncate(int fd,off_t len);

         Int truncate(char * path,off_t len);

 

IO 多路复用

6.Select

头文件

         #include<sys/time.h>

         #include<sys/types.h>

         #include<unistd.h>

函数原型:

         Int select(int n,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

 

         n 所有集合中文件描述符最大值加一

         timeout 结构体

         #include<sys/time.h>

         Struct{

         Long tv_sec;//seconds

         Long tv_usec; //microseconds

         };

Select返回时这个结构体状态未定义,最好重新初始化,较新版本会把他初始化为剩余时间

如果时间为0,select立即返回,报告文件描述符不可用,不在等待后续操作。

 

管理文件描述符宏定义

         FD_CLR(int fd,fd_set *set);

         FD_ISSET(int fd,fd_set *set); //测试一个文件描述符是否在集合内

FD_SET(int fd,fd_set *set); //添加一个文件描述符到指定集合

FD_ZERO(fd_set *set);  //移除指定集合中所有描述符 ,每次调用select()前调用

 

文件描述符集合是静态建立的,最大值有限制,为 FD_SETSIZE; linux 为1024

        

通过将select 三个集合设置为0 ,将超时设置为非空可以实现sleep;

 

7.Pselect

posix版本的select

头文件

#include<sys/select.h>

 

#define _XOPEN_SOURCE 600

原型

         Int pselect(int n,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,

Const struct timespec *timeout,

Const sigset_t * sigmask);

和select比区别

超时参数类型改变,pselect 使用timespec精度为秒和纳秒,比秒和毫秒精度高,事实是都在秒之后不可靠

Pselect 不修改timeout参数

Select没有sigmask参数,pselect添加是为了解决信号和文件描述符之间的竞争条件

一般还是选择使用select

 

 

注意:

Select在有文件描述符状态变化时返回,返回时修改了文件描述符集合,返回后的集合中只有状态改变的fd,每次使用时要重新赋值。

8.Poll

System v 的I/O多路复用

头文件:

         #include<sys/poll.h>

函数原型:   

       Int poll(struct pollfd *fds,unsigned int nfds, int timout);

 

Pollfd 结构

头文件

#include<sys/poll.h>

 

Struct pollfd

{     int fd;  //文件描述符

       Short event;// 监视的文件描述符上的事件位掩码

       Short revent;// 发生在文件描述上的事件位掩码

}

常量

说明

POLLIN

普通或优先级带数据可读

POLLRDNORM

普通数据可读

POLLRDBAND

优先级带数据可读

POLLPRI

高优先级数据可读

POLLOUT

普通数据可写

POLLWRNORM

普通数据可写

POLLWRBAND

优先级带数据可写

POLLERR

发生错误

POLLHUP

发生挂起

POLLNVAL

描述字不是一个打开的文件

 

 

注意:

Poll在返回后只修改了fds的revents字段,所以可以反复使用。

与select区别。

 

9.Ppoll

和pselect 类似

 

 

 

 

 

 

 

 

 

 

 

 

 

标准I/O

打开文件

10.fopen()

头文件

         #include<stdio.h>

函数原型:

         FILE* fopen(const char* path,const char *mode);

 

文件打开后关联到一个新的流

打开方式有: r r+ w w+ a a+

成功返回指针,失败返回NULL。

11.fdopen

头文件

#include<stdio.h>

函数原型:

FILE* fdopen(int fd,const char *mode);

讲一个打开的文件的描述符转化为流,转化时mode要一致

12.fclose

头文件

#include<stdio.h>

函数原型:

         Int fclose(FILE * stream);

成功返回0 并将缓冲中没写入数据写入,失败返回EOF

13. fcloseall

#include <stdio.h>

#define _GUN_SOURCE

Int fcloseall();

 

 

 

14.fgetc()

#include<stdio.h>

Int fgetc(FILE*stream);

 

函数结果必须以int保存 ,EOF会被返回,输出时要检查 c== EOF

 

15.ungetc()

#include<stdio.h>

Int ungetc(int c,FILE*stream);

 

成功返回0,失败返回EOF;

 

16.fgets

#include<stdio.h>

Char * fgets(char *str,int size,FILE* stream);

读取size-1 个字节到str,成功返回str失败返回NULL。

读到EOF或者换行符的时候结束,如果读到换行符就写入str。

最大输入长度为LINE_MAX 在limits.h中定义

 

17.fread

 

18.fputc()

#include<stdio.h>

Int fputc(int c,FILE *stream);

 

19fputs()

#include<stdio.h>

Int fputs(const char *str,FILE *stream);

20. fwrite

21.fseek()

#include<stdio.h>

Int fseek(FILE *stream,long offset,int whence);

 

Whence有如下值:

SEEK_CUR 文件位置为 当前加offset

SEEK_END文件位置为文件尾加offset

SEEK_SET文件位置为0+offset

 

错误返回-1;正确返回0

 

22.fsetpos()

#include<stdio.h>

Int fsetpos(FILE * stream,fpos_t *pos);

 

23.rewind

#include<stdio.h>

Void rewind(FILE* stream);将流置于初始位置

 

24 ftell()

#include<stdio.h>

long ftell(FILE* stream);

返回文件的当前流位置。错误返回-1.

 

 

25fgetpos

#include<stdio.h>

int fgetpos(FILE* stream,fpos_t *pos);

 

 

26.fflush

#include<stdio.h>

Int fflush(FILE* stream);  将流中数据写回文件

成功返回0;

 

Int ferror  检查是否有错

Int feof     检查是否文件尾

Void clearer 清空失败和文件尾标志,不可恢复

 

27.fileno

#include<stdio.h>

Int fileno (FILE *stream);

返回文件描述符失败返回-1;

28.Setvbuf

#include<stdio.h>

Int setvbuf(FILE * stream, char * buf, int mode, size_t size);

_IONBF

_IOLBF

_IOFBF

函数在除了无缓存模式下,buf可以指向一个size大小的缓冲区,如果buf为空则glic分配

Stdio.h中的BUFSIZE定义默认的缓冲区大小

29.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);

 

从iov描述的缓冲区读或者写count个segment的数据到fd。

 

Struct iovec 描述的缓冲区成为segment

#include<sys/uio.h>

Struct iovec

{

Void *iov_base;

Size_t iov_len;

}

 

30.epoll

#include<sys/epoll.h>

Int epoll_create(int size);

返回与这个实例关联的文件描述符  size为要监测的文件描述符数目。出错返回-1

 

EINVAL  size不是正数

ENFILE      系统打开文件数达到上限

ENOMEN 没有足够内存

 返回的文件描述符需要用close关闭。

 

#include<sys/epoll.h>

Int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);

 

#include<sys/epoll.h>

Struct epoll_event{

_u32 events;

Union{

Void *ptr;

Int fd;

_u32 u32;

_64 u64;

} data;};

Epoll_ctl 调用会关联epoll实例和epfd, op指定要进行的操作,event描述更具体的行为

Op的取值

EPOOL_CTL_ADD   把fd加到监测列表

EPOOL_CTL_DEL      删除fd到监测列表

EPOOL_CTL_MOD   使用event修改监测列表中的fd

 

Event取值:

EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT:表示对应的文件描述符可以写;

EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

EPOLLERR:表示对应的文件描述符发生错误;

EPOLLHUP:表示对应的文件描述符被挂断;

EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要使用epoll_ctl_mod修改fd

 

#include<sys/epoll.h>

Int epoll_wait ( int epfd,struct epoll_event * events,int maxevents,int timeout );

Timeout  毫秒

返回成功 events指向epoll_event结构体,其中最多有maxevents 返回值为事件个数,出错返回-1

 

 

边缘触发和水平触发

Epoll_ctl中events设置为 RPOLLE时,设置边缘触发。

例子:

  1. 生产者向管道写入数据1KB
  2. 消费者管道调用epoll_wait等待数据。

在边缘触发中,直到1数据写完epoll_wait才返回,水平触发则epoll_wait立即返回

水平触发为默认形式,select和poll都是水平模式。水平触发只关心状态,边缘触发关系事件。

 

 

 

 

 

 

 

 

 

 

 

 

内存映射

 

31.Mmap

#include<sys/mman.h>

void* mmap(void* addr,size_t len,int prot,int flags,int fd,off_t offset);

addr 参数告诉内核映射文件的最佳地址,只是提示不是强制。一般设置为 0;调用返回内存映射的开始地址。

Prot 设置访问权限 PROTNONE 无法访问,一般这样设置没有意义。

PROT_READ     可读

PROT_WRITE   可写

PROT_EXEC      可执行

访问的权限不能与打开文件的访问模式冲突。

Flag参数描述了映射的类型和一些行为

MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。

MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者()被调用,文件实际上不会被更新。

MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。

MAP_DENYWRITE //这个标志被忽略。

MAP_EXECUTABLE //同上

MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时,对映射区的修改会引起段违例信号。

MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。

MAP_GROWSDOWN //用于堆栈,告诉VM系统,映射区可以向下扩展。

MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。

MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。

MAP_FILE //兼容标志,被忽略。

MAP_32BIT //将映射区放在进程的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。

MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。

MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立入口。

fd:有效的。一般是由()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。

off_toffset:被映射对象内容的起点。

成功返回映射区域的地址

SIGBUS   //进程访问无效的映射去死产生

SIGSEGV  //进程试图在只读映射区写入数据时产生。

32.Sysconf

#include<unistd.h>

Long sysconf(int name);

返回name属性的值失败返回-1.

例子: long pagesize = sysconf(SC_PAGR_SIZE);获取页面大小

#include<unistd.h>

Int getpagesize(void);

 

#include<asm/pages.h>

Int page_size = PAGE_SIZE;

33.munmap

#include<sys/mman.h>

int munmap(void* addr,size_t len);

 

移除从addr开始的len字节长度的映射。移除后访问会产生SIGSEGV信号

成功返回0,失败返回-1;

34.mremap()

#include<sys/mman.h>

#include<unistd.h>

#define _GNU_SOURCE

Void * mremap(void *addr,size_t old_size,size_t new_size,unsigned long flags);

修改文件大小size 从old到new

35.mprotect

#include<sys/mman.h>

Int mprotect(const void *addr,size_t len,int prot);

修改映射区域权限

在有些系统中mprotect只能修改mmap分配的区域,在linux可以修改所有的

 

 

36.msync

#include<sys/mman.h>

Int msync(void *addr,size_t len,int flags);

Flag 取值

MS_ASYNC 同步操作一部发生,系统调度更新,mysnc立即返回。

MS_INVALIDATE 所有该块映射的拷贝失效,未来对该映射的操作直接写到硬盘

MS_SYNC 所有同步同步进行,在write执行完毕后msync才返回。

 

#include<sys/mman.h>

Int Madvise(void *addr,size_t len,int len);

 

#include<fcntl.h>

Int posix_fadvise(int fd ,odd_t offset,off_t len,int advise);

 

#include<fcntl.h>

Ssize_t readahead(int fd ,off64_t offset,size_t count);

 

同步Synchronized ,同步Synchronous 异步asynchronous

同步在读写操作执行完之后才返回。

异步不用读写操作执行完就可以返回

Synchronized保证事件发生,属于更深层次,NoSynchronized写操作加入队列就返回,只确保到内核缓存区域。

 

本类排行

今日推荐

热门手游