POSIX标准IO操作
来源:互联网 发布:配音软件 编辑:程序博客网 时间:2024/05/21 17:04
POSIX标准IO操作
一:ANSI C与 Posix C
ANSI C库函数是在用户态实现,流的相应资源也存在于用户态,但无论如何实现,最终要通过内核实现对文件的读写控制。因此,在fopen()系列函数中必然调用了对操作系统的系统调用,这一系统调用在Linux系统下即为open,close,write和read等函数,这些函数都遵循posix标准。
其实ANSI C库IO函数是对posix函数的封装,在其基础上加了流的概念,并在用户空间申请了流资源,这样处理显然增加了程序的灵活性和可以执行。
文件流和文件描述符的转换函数
1,int fileno (FILE *stream)
此函数一每个流为对象,返回该流的文件描述符值,如果失败返回-1
2,FILE *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操作方式。
- POSIX标准IO操作
- POSIX标准IO操作
- POSIX标准下文件IO管理
- 标准IO文件操作
- C++标准IO操作
- 文件操作 标准IO
- POSIX系统编程之IO操作
- POSIX标准
- POSIX标准
- POSIX 标准
- POSIX标准
- Posix标准
- Posix标准
- POSIX标准
- C++ 标准库 IO 操作
- C++ 标准库 IO 操作
- 标准c的io操作
- C标准IO的操作
- Android-vold源码分析之startListener(6)
- 第8周实验报告1
- String.Format数字格式化输出 {0:N2} {0:D2} {0:C2}
- Android-vold源码分析之runCommand(7)
- 第八周实验报告任务1 实现复数类中的运算符重载
- POSIX标准IO操作
- Android-vold源码分析之挂载SD卡(8)
- 灰色div+css导航菜单栏代码
- 单精度和双精度
- Android-vold源码分析之卸载SD卡(9)
- Android-vold源码分析之格式化SD卡(10)
- ANSI C标准文件IO操作
- 奇怪的 error C2143: syntax error : missing ';' before 'type'
- 我老师教的非常简洁的javascropt日历Js