与文件相关的系统调用

来源:互联网 发布:权力的48条法则 知乎 编辑:程序博客网 时间:2024/04/29 03:26

一、低级文件I/O

1、系统调用:

open( ),read( ),write( ),lseek( ),close( ),fcntl( ), ioctl( )

2、文件描述

当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用open或creat返回的文件描述符标识该文件,将其作为参数传送给read、write、lseek和close等。

按照惯例,UNIX shell使文件描述符:

0-stdin 1-stdout 2-stderr

在POSIX.1应用程序中,标准I/O描述符被定义为:

0-STDIN_FILENO; 1-STDOUT_FILENO;  2-STDERR_ FILENO

这些常数都定义在头文件<unistd.h>中。

文件描述符的范围是0 ~ OPEN_MAX。早期的UNIX版本采用的上限值是1 9 (即2 0),现在很多系统则将其增加至6 3且可以以内核参数的办法设置,比方说1024。

3、原始系统数据类型

在UNIX/Linux的开发过程中用到的以_t结尾的数据为系统原始数据。

系统原始数据在头文件<sys/types.h>中被定义。<unistd.h>包含此头文件。

4、出错处理

UNIX函数出错时,往常返回一个负值,而且整型变量errno通常设置为具有特定信息的一个值。例如,open函数如成功执行则返回一个非负文件描述符,如出错则返回-1。

在open出错时,有大约1 5种不同的errno值。某些函数并不返回负值而是使用另一种约定。例如,返回一个指向对象的指针的大多数函数,在出错时,将返回一个null指针。

文件<errno.h >中定义了变量errno以及可以赋与它的各种常数。这些常数都以E开头。

在Linux系统中,errno定义在头文件/usr/include/asm/errno.h,多达124条。

1)errno

POSIX定义errno为:extern int errno;

对于errno应当知道两条规则:

(1) 如果没有出错,则其值不会被一个例程清除。因此,仅当函数的返回值指明出错时,才检验其值。

(2) 任一函数都不会将errno值设置为0,在<errno.h>中定义的所有常数都不为0。 

2)错误处理的标准函数

(1)strerror( ):

功能:以字符串方式打印错误信息。

用法:

#include <string.h>

char *strerror(int  errnum) ;

返回:指向消息字符串的指针。

(2)perror()

功能:在标准错误上产生一条基于errno的当前值出错消息。

用法:

#include <stdio.h>

void perror(const char * msg) ;

输入:首先输出由msg指向的字符串,然后是一个冒号,一个空格,然后是对应于errno值的出错信息,然后是一个新行符。

(3)处理错误的例子

#include<errno.h>main(int argc, char *argv[ ]){fprintf(stderr, “EACCES: %s\n”,strerror(EACCES);errno=ENOENT;perror(argv[0]);}


输出:假设,编译后生成a.out,则输出为:

EACCES: Permission denied

./a.out: No such file or directory

二、系统调用

(1) open

open可以打开或创建一个文件,并返回一个文件描述符。

调用方法:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char * pathname, int oflag) ;

int open(const char * pathname, int oflag, mode_t mode ) ;

返回值:成功时为文件描述符,出错则为-1。

open的参数

pathname是要打开或创建的文件的名字。

oflag参数可用来说明此函数的多个选择项。用下列一个或多个常数进行或运算构成oflag参数(在fcntl.h中):

• O_RDONLY:只读打开。 • O_WRONLY:只写打开。

• O_RDWR :读写打开 • O_APPEND 追加方式。

• O_CREAT 若不存在则创建它。需同时使用第三个参数mode。

• O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。

• O_TRUNC 如果此文件存在,则将其长度截短为0。

• O_NOCTTY 如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。

• O_NONBLOCK 如果pathname指的是特殊文件,此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。

(2) creat

功能:创建一个新文件

用法:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int creat(const char * pathname, mode_t mode) ;

返回:成功为只写打开的文件描述符;出错为-1。

注意:此函数等效于:

open (pathname, O_WRONLY|O_CREAT|O_TRUNC, mode);

(3) read

功能:从描述符为filedes的文件读信息。

用法:

#include <unistd.h>

ssize_t read(int filedes, void *buff, size_t nbytes);

返回:读到的字节数,若已到文件尾为0,若出错为-1。

 在UNIX/Linux 可重定义为: 

int read(int fd,  char  *buff,  unsigned nbytes);

(4) write

功能:向已打开的文件写数据。

用法:

#include <unistd.h>

ssize_t write(int filedes, const void * buff, size_t nbytes) ;

返回值:若成功为已写入的字节数;出错为-1。

int write(int fd,  char  *buff,  unsigned nbytes);

(5) 文件位置指针

文件位置指针:每个打开文件都有一个与其相关联的“当前位移量”。是从文件开始处计算的字节数。通常,读、写操作都从当前文件位置处开始,并使位移量增加所读或写的字节数。

按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0,即指向文件的开始处。

文件位置指针可以通过系统调用lseek来移动。

(6) lseek

功能:显式地定位一个打开文件的位置指针。

用法:

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int filedes, off_t offset, int whence) ;

返回值:若成功为新的文件位移,若出错为-1。

说明:对参数offset 的解释与参数whence的值有关:

whence=SEEK_SET(0),从文件开始。

whence=SEEK_CUR(1),从当前位置, offset可正可负。

whence=SEEK_END(2),从文件末尾, offset可为正或负。

例:求文件的当前位置指针:

off_t currpos; currpos = lseek(fd, 0, SEEK_CUR);

这种方法也可用来确定所涉及的文件是否可以设置位移量。如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE。

(7) fcntl

功能:控制和改变已经打开文件的属性。

用法:

#include <sys/types.h>

#include <unistd.h>

#include <fcntl.h>

int fcntl(int filedes, int cmd, long arg );

int fcntl(int filedes, int cmd, struct flock *lock );

返回值:若成功则依赖于cmd(见下),若出错为-1

fcntl函数有五种功能

• 复制一个现存的描述符(cmd=F_DUPFD),新文件描述符作为函数值返回。它是尚未打开的各描述符中大于或等于第三个参数值中各值的最小值。新描述符与filedes 共享同一文件表项;

• 获得/设置文件描述符标记(cmd=F_GETFD/F_SETFD);对应于filedes的文件描述符标志作为函数值返回。

• 获得/设置文件状态标志(cmd=F_GETFL / F_SETFL);新标志值按第三个参数设置。可以更改的几个标志是:O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC。

• 获得/设置异步I/O有权(cmd=F_GETOWN/F_SETOWN);获取或接收当前接收SIGIO和SIGURG信号的进程ID或进程组ID。

• 获得/设置记录锁(cmd=F_GETLK, F_SETLK或F_SETLKW)。

(8) ioctl函数

ioctl 函数是I/O操作的杂物箱。不能用本章中其他函数表示的I/O操作通常都能用ioctl表示。

终端I/O是ioctl的最大使用方面(第11章将介绍POSIX.1已经用新的函数代替ioctl进行终端I/O操作)。

Ioctl更多的是用于设备控制,比如磁盘的格式化,MODEM设备,磁带的快进、快倒等。

例子

#include<errno.h>#include<sys/stat.h>#include<sys/fcntl.h>main( ){ intfd, j;char*myc="This is my 1st program!!\n";char*myf="myfile";if((fd=open(myf,O_RDWR|O_CREAT|O_APPEND,0644))==-1) {perror(myf); exit(errno);}if(write(fd,myc,strlen(myc))!=strlen(myc)){perror(myc); close(fd);exit(errno);}close(fd);}


0 0