POSIX标准IO操作

来源:互联网 发布:配音软件 编辑:程序博客网 时间:2024/05/21 17:04

POSIX标准IO操作

分类: linux系统编程 61人阅读 评论(0) 收藏 举报

一:ANSI C与 Posix C

ANSI C库函数是在用户态实现,流的相应资源也存在于用户态,但无论如何实现,最终要通过内核实现对文件的读写控制。因此,在fopen()系列函数中必然调用了对操作系统的系统调用,这一系统调用在Linux系统下即为openclosewriteread等函数,这些函数都遵循posix标准。

其实ANSI CIO函数是对posix函数的封装,在其基础上加了流的概念,并在用户空间申请了流资源,这样处理显然增加了程序的灵活性和可以执行。

文件流和文件描述符的转换函数

1int fileno (FILE *stream)

此函数一每个流为对象,返回该流的文件描述符值,如果失败返回-1

2FILE *fdopen (int fd , char *modes)

该函数实现每个流于一个文件描述符连接,第一个参数为文件描述符,第二个参数为封装该流的权限,如果执行成功,返回一个流对象,失败返回NULL

、打开/关闭文件

1

名称:

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

参数:

pathname   文件名

    

flags         打开模式

返回值:

-1    遇到错误

    

int   打开成功,返回文件描述符。

这个系统调用在进程和文件之间建立一条连接 ,这个连接被称为文件描述符,它就像一条由进程通向内核的管道。

要打开一个文件,必须指定文件名和打开模式,有3种打开模式:只读,只写,可读可写,分别对应于O_RDONLY,O_WRONLY,O_RDWR,这在头文件/usr/include/fcntl.h中有定义。

      打开文件是内核提供的服务,如果在打开过程中内核检测到任何错误,这个系统调用就会返回-1。错误的类型是各种各样的,如:要打开的文件不存在。即使文件存在可能因为权限不够而无法打开,在open的联机帮助中列出了各种可能的错误,大家可以看看。

      UNIX允许一个文件被多个进程访问,也就是说当一个文件被一个进程打开后,这个文件还可以被其它进程打开。

     如果文件被顺利打开内核会返回一个正整数的值,这个数值就叫文件描述符,文件描述符是是一个简单的整数,用以标明每一个被进程所打开的文件,描述符0代表标准输出,对应的宏是STDOUT_FILENO,描述符1代表标准输入,对应的宏为STDIN_FILENO,描述符2代表标准错误输出,对应的宏为STDERR_FILENO,系统给进程分配描述符都是从3开始的,如果同时打开好几个文件,它们所对应的的文件描述符是不同的,如果一个文件打开多次,对应的文件描述符也不相同。必须通过文件描述符对文件操作。

下列是参数flags 所能使用的:

必选项:以下三个常数中必须指定一个,且仅允许指定一个。

O_RDONLY 以只读方式打开文件

O_WRONLY 以只写方式打开文件

O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。

以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。

O_CREAT 若欲打开的文件不存在则自动建立该文件。

O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。

O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。

O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。

O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。

O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。

O_NDELAY 同O_NONBLOCK。

O_SYNC 以同步的方式打开文件。

O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。

O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。

如果打开的文件不存在,则可以使用open函数自动创建文件,即“O_CAEAT”打开方式,此时需要用到第三个参数。

第三个参数mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r--r--,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示,参数mode 则有下列数种组合,只有在建立新文件时才会生效,文件权限由open的mode参数和当前进程的umask掩码共同决定,因此该文件权限应该为(mode-umaks)。

S_IRWXU00700 权限,代表该文件所有者具有可读、可写及可执行的权限。

S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。

S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。

S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。

S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。

S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。

S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。

S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。

S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。

S_IROTH 00004 权限,代表其他用户具有可读的权限

S_IWOTH 00002权限,代表其他用户具有可写入的权限。

S_IXOTH 00001 权限,代表其他用户具有可执行的权限。

 

返回值 若所有欲核查的权限都通过了检查则返回0 值,表示成功,只要有一个权限被禁止则返回-1。

 

错误代码 EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。

EACCESS 参数pathname所指的文件不符合所要求测试的权限。

EROFS 欲测试写入权限的文件存在于只读文件系统内。

EFAULT 参数pathname指针超出可存取内存空间。

EINVAL 参数mode 不正确。

ENAMETOOLONG 参数pathname太长。

ENOTDIR 参数pathname不是目录。

ENOMEM 核心内存不足。

ELOOP 参数pathname有过多符号连接问题。

EIO I/O 存取错误。

2

名称:

close

目标:

关闭一个文件。

头文件:

#include < unistd.h>

函数原形:

int close(int fd)

参数:

fd   文件描述符

返回值:

-1    遇到错误

    

int   关闭成功,返回文件描述符。

      Close这个系统调用会关闭进程和文件fd之间的连接,如果关闭过程中出现错误,close返回-1,如:fd所指的文件并不存在。关闭成功则返回文件描述符。

 

3.

名称:

creat

目标:

创建/重写一个文件

头文件:

#include <sys/types.h>

#include <stat.h>

#include < fcntl.h>

函数原形:

int creat(const char *pathname,mode_t mode)

参数:

pathname  文件名

 

mode     访问模式

返回值:

-1        遇到错误

    /

fd        创建成功,返回文件描述符

      Creat告诉内核创建一个名为filename的文件,如果这个文件不存在,就创建它,如果已经存在,就把它的内容清空,把文件的长度设为0。    

      如果内核成功地创建了文件,那么文件的许可位(permission bits)被设置为由第二个参数mode所指定的值.如:

fd=creat(“addressbook”,0644);

      创建一个名为addressbook的文件,如果文件不存在,那么文件的许可位被设为rw-r-r—.

如果文件已存在它的内容会被清空。任一情况下,fd都会是指向addressbook的文件描述符。

、文件的读取和写入

4

名称:

read

目标:

把数据读到缓冲区。

头文件:

#include < unistd.h>

函数原形:

ssize_t read(int fd, void *buf, size_t count)

参数:

fd      文件描述符

 

buf     用来存放数据的目的缓冲区

 

count    要读取的字节数

返回值:

-1      遇到错误

    

numread 成功关闭,返回所读取的字节数目。

read这个系统调用请求内核从fd所指定的文件中读取qty字节的数据,存放到buf所指定的内存空间中,内核如果成功地读取了数据,就返回所读取的字节数目。否则返回-1

当文件的字节数没有你想要的那么多时,read就会判断下一个数值是不是’/0’,如果是就停止读取,然后退出。numread返回的是’/0’之前的字节数,也就是是原文件的字节数而不是你想读的字节数。

5.

名称:

write

目标: 

将内存中的数据写入文件。

头文件:

#include < unistd.h>

函数原形:

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

参数:

fd      文件描述符

 

buf     内存数据

 

count   要写的字节数

返回值: 

-1      遇到错误

    

Num written 成功写入,返回写入的字节数目。


在实际的写入过程中,可能会出现写入的字节数少于所要求的。这可能有两个原因,第一是有的系统对文件的最大尺寸有限制,第二是磁盘空间接近满了。在上述两种情况下内核都会尽力把数据往文件中写,并将实际写入的字节数返回,所以调用write后都必须检查返回值是否与要写入的相同,如果不同就要采取相应的措施。

      学完上面几个系统调用,我们就可以自己编写的cp命令了。它的基本思路是从原文件读取数据写入缓冲,再将缓冲的数据写入目标文件。


 

三、文件描述符操作函数

6

名称::

lseek

目标:

使指针指向文件中的指定位置。

头文件:

#include <sys/types.h>

#include <unistd.h>

函数原形: 

off_t lseek(int fildes,off_t offset,int whence)

参数:

fildes    文件描述符

offset   移动的距离

wence  SEEK_SET=>文件的开始

       SEEK_CUR=>当前位子

       SEEK_END=>文件结束

返回值:

-1     遇到错误

Ildpos  指针变化前的位子


      lseek改变文件描述符所关联的指针的位置,新的位置由offset和wence来指定,wence是基准位置,基准位子可以是文件的开始(0)、当前位子(1)或文件的结束(2)。 offset是从基准位子开始的偏移量。若wence为SEEK_SET,该文件的偏移设置为距文件开始处offset个字节数。若wence是SEEK_CUR,该文件的偏移设置为其当前值加offset, offset可为正或负。若wence是SEEK_END,该文件的偏移设置为文件长度加offset, offset可为正或负。

      lseek(fd,0,SEEK_END);

      文件位偏移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中没有写过的字节都被读为0

7.

名称::

dup/dup2

目标:

复制一个现存的文件描述符.

头文件:

#include <unistd.h>

函数原形: 

int dup(int oldfd)

int dup2(int oldfd,int newfd)

参数:

oldfd   原有文件描述符 

newfd  新的文件描述符

返回值:

-1     遇到错误

int     新文件描述符

  系统调用dup是用来复制一个文件描述符,也就是将进程u区的文件描述符表中的一项复制一份,使得这两项同时指向系统稳健表的同一表项。

  系统调用dup复制由参数oldfd指定的文件描述到进程文件描述符表的第一个空表项处。而系统调用dup2复制由参数oldfd指定的文件描述到参数newfd指定的文件描述符表项处。老的文件描述符和新复制的文件描述符可以互换使用。它们共享锁、文件指针和文件状态。例如,对其中一个文件描述符使用系统调用lseek修改文件指针的位置,对另一文件描述符来说文件指针也改变了,其实我们了解了内核的工作原理,这一点很容易理解。因为我们知道,文件指针是放在系统文件表中的。但这两个文件描述符具有不同的close-on-exec标志,因为该标志是存放在文件描述符表中的。

  该调用成功时,返回值为新的描述符;错误时,返回-1,并设置相应的错误代码errno:

EBADF:参数oldfd不是一个已经打开的文件描述符;或者参数newfd超出允许的文件描述符的取值范围。 

EMFILE:进程打开的文件描述符数量已经到达最大值,但仍然企图打开新的文件描述符。 

  下面我们来看一个简单的例子。在这个例子中,我们将标准输出(文件描述符为1)关闭,并将一个打开了普通文件“output”的文件描述符复制到标准输出上,因为刚关闭了文件描述符1,所以,文件描述符表的第一个空表项是1。所以,程序以后的printf等向标准输出写的内容都写到了文件中。

利用这个功能我们可以把输出/输入重定向到文件中。下面是一个例子。

dup2的功能和dup基本相同,只不过是dup2复制oldfd到newfd上。下面是用dup2实现同样的例子。

 

利用这两个函数我们可以实现管道的功能,有关管道的内容将在后面介绍。

 

8

名称::

fcntl

目标:

改变已经打开文件的性质。

头文件:

#include <unistd.h>

#include <sys/types.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);

参数:

fd      文件描述符

cmd    功能描述位

fcntl函数有5种功能:

1      复制一个现存的文件描述符(cmd=F_DUPFD

2        获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD

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

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

5        获得/设置记录锁(cmd=F_GRTLK,F_SETLK或F_SETLKW

 

fcntl的功能之一是重复文件描述字。

fcntl (FileDescriptor, F_DUPFD, 0)等价于Dup(FileDescriptor)

close (New); fcntl(Old, F_DUPFD, New)等价于dup2 (Old,New)

 

fcntl的功能之二获得/设置文件描述符标记。

获得文件描述标记fcntl (FileDescriptor, F_GETFD)

设置文件描述标记fcntl(FileDescriptor, F_SETFD, flags)

 

fcntl的功能之三获得/设置文件状态标签,文件状态标签分为3类它们是文件访问方式、打开时标志和I/O操作方式。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 捡到苹果手机不知道id密码怎么办 平板不知道id地址和密码怎么办 红米1s刷机变砖了怎么办 车玻璃被鞭炮炸了黑印子怎么办 出轨的事被家人知道后道处传怎么办 村霸霸占土地弱势村民该怎么办? 户户通没有插卡位置信息改变怎么办 出现重大污染天气时企业该怎么办 电子税务句注册后未绑定企业怎么办 报税的时候PIN码忘了怎么办 购房合同丢失开发商不给补怎么办 租赁合同丢了房东不退押金怎么办 小孩不愿意喝奶粉爱喝乳酸菌怎么办 长安通不记名卡丢了怎么办 农村电表箱里的开关坏了怎么办 建行手机银行登录密码忘了怎么办 手机银行登入密码忘记了怎么办 邮政手机银行登录密码忘了怎么办 建设手机银行登入密码忘记了怎么办 浪琴机械表秒针走的快怎么办 雷达晶萃陶瓷表镀金掉色怎么办 做信息稿部分人员没拍到照片怎么办 二建条件不够考后审核怎么办 学校官网的教务系统忘记密码怎么办 已参加两次高考失败还想复读怎么办 我高考失利想补习学藉怎么办 本科毕业证上是1寸照片怎么办 老婆父母不给户口本迁户口怎么办 深圳夫妻投靠双方再婚的网上怎么办 老人档案丢了要继承公证怎么办 农民把户口迁入城市后宅基地怎么办 离婚了再婚带孩子在上海上学怎么办 上班几天被公司辞退不发工资怎么办 在单位工作被领导边缘化该怎么办 退休人员户口迁到外地退休金怎么办 招工表填写和实际的有误怎么办 招工时档案年龄有人为改动怎么办 8个月宝贝还不会坐怎么办 朗动导航黑屏过了保修期怎么办 平板突然黑屏开不了机了怎么办 苹果ipad锁屏密码忘了怎么办