Chinaunix首页 | 论坛 | 博客
  • 博客访问: 130780
  • 博文数量: 75
  • 博客积分: 1485
  • 博客等级: 上尉
  • 技术积分: 720
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-11 20:57
文章分类
文章存档

2011年(1)

2010年(15)

2009年(59)

我的朋友

分类: LINUX

2009-06-01 09:20:14

一、文件描述符
  文件描述符是非负整数,当open或creat文件时,向进程返回文件描述符。
   文件描述符0,1,2分别与标准输入,标准输出,标准出错相对应。
   在POSIX标准中,0,1,2分别换成符号常数STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO。这些常数定义在中。
 
二、open函数
  

#include <fcntl.h>
int open(const char *pathname,int oflag,```); //仅当open创建文件时才使用第三个参数

oflag参数主要有:

  O_RDONLY   只读

  O_WRONLY   只写

  O_RDWR     读写                  

这些参数都定义在中。

open返回的文件描述符一定是最小的未用描述符数字。

三、creat函数

#include <fcntl.h>
int creat(const char *pathname,mode_t mode); 
   //若成功返回只写打开的文件描述符

等价于

#include <fcntl.h>
int open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mode);

其不足是创建的文件只能只写打开,可改为如下方式:

#include <fcntl.h>
int open(pathname,O_RDWR|O_CREAT|O_TRUNC,mode);

三、close函数

#include <unistd.h>   //注意头文件
int close(int filedes);

四、lseek函数

#include <unistd.h>
off_t lseek(int filedes,off_t offset,int whence);
       //若成功返回新文件偏移量

参数offset与whence有关

若whence为SEEK_SET,偏移量为文件开始处的offset字节。

若whence为SEEK_CUR,偏移量为文件当前值加offset字节,offset可正可负。

若whence为SEEK_END,偏移量为文件长度加offset字节,offset可正可负。

 

#include "apue.h"
#include <fcntl.h>

char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";

int main(void)
{
   int fd;
   if ((fd = creat("file.hole", FILE_MODE)) < 0)  //别忘创建文件的""
      err_sys("creat error");
   if (write(fd, buf1, 10) != 10)
      err_sys("buf1 write error");
 /* offset now = 10 */
   if (lseek(fd, 16384, SEEK_SET) == -1)
      err_sys("lseek error");
 /* offset now = 16384 */
   if (write(fd, buf2, 10) != 10)
      err_sys("buf2 write error");
 /* offset now = 16394 */
   exit(0);
}

(1)FILE_MODE在apue.h中定义:

  #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

S_IRUSR
  Permits the file's owner to read it.
S_IWUSR
  Permits the file's owner to write to it.
S_IRGRP
  Permits the file's group to read it.
S_IWGRP
  Permits the file's group to write to it.

(2)err_sys在apue.h中定义,也可用perror。

(3)测试lseek返回值最好测试其是否为-1,而不是测试其是否小于0,因为有些文件偏移量可以小于0。

五、read函数

#include <unistd.h>
ssize_t read(int filedes,void *buf,size_t nbytes);

返回值为读取的字节数,如果读到文件的结尾则返回0,出错返回-1.

六、write函数

#include <unistd.h>
ssize_t write(int filedes,const void *buf,size_t nbytes);

返回值通常等于nbytes的值,否则出错。

七、原子操作

  pread和pwrite函数

#include <unistd.h>
ssize_t pread(int filedes,void *buf,size_t nbytes,off_t offset);
                           //返回值和read相同
ssize_ pwrite(int filedes,void *buf,size_t nbytes,off_t offset);
                          //返回值和write相同

调用pread相当于顺序调用lseek和read函数。但有点不同:

        • 调用pread时,无法中断其定位和读操作。

        • 不更新文件指针。

同理,调用pwrite相当于调用lseek和write函数。

一般而言,原子操作指的是由多步组成的操作。如果原子操作执行,所有的子操作都执行。不执行的话所有的子操作都不执行。

八、dup和dup2函数

以下函数复制一个存在的文件描述符

#include <unistd.h>
int dup(int filedes);
int dup2(int filedes,int filedes2);
          //成功则均返回新的文件描述符,出错返回-1

   对于dup2,我们通过filedes2参数指明新的文件描述符,如果filedes2已经打开,则先关闭。如果filedes等于filedes2,则dup2返回filedes2而不关闭它。

九、fcntl函数

fcntl函数能够改变一个已打开文件的性质

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

fcntl有以下几个作用(根据cmd参数的不同):

1.复制存在的描述符(cmd=F_DUPFD)

2.获得/设置文件描述符标志(F_GETFE/F_SETFD)

3.获得/设置文件状态标志(F_GETFL/F_SETFL)

4.获得/设置异步I/O所有权(F_GETOWN/F_SETOWN)

5.获得/设置记录锁(F_GETLK/F_SETLK或F_SETLKW)

   对于这两种操作,可以获得或者设置文件的状态标志。F_GETFL时可以获得O_RDONLY、O_WRONLY、O_RDWR、O_APPEND、O_NONBLOCK、O_SYNC和O_ASYNC。对于前三种标志,必须使用屏蔽字O_ACCMODE,然后将结果与这三种标志一一比较。F_SETFL时只能设置后四种标志。
    accmode = val & O_ACCMODE;
    if (accmode == O_RDONLY) …
    else if (accmode == O_WRONLY) …
    else if (accmode == O_RDWR) …
    else err_dump("unknown access mode");
    
    if (val & O_APPEND) …
    if (val & O_NONBLOCK) …
    ……

以下程序第二个参数指定文件描述符,并对于该描述符打印其所选择的文件标志说明。
 

#include "apue.h"
#include <fcntl.h>

int main(int argc ,char *argv[])
{
    int val;
    if(argc!=2)
        err_quit("usage:a.out ");
    if((val=fcntl(atoi(argv[1]),F_GETFL,0))<0)
        err_sys("fcntl error for fd %d",atoi(argv[1]));
    switch(val&O_ACCMODE)
    {
    case O_RDONLY:printf("read only");break;
    case O_WRONLY:printf("write only");break;
    case O_RDWR:printf("read write");break;
    default:err_dump("unknown access mode");
    }
    if(val&O_APPEND)
        printf(",append");
    if(val&O_NONBLOCK)
        printf(",nonblocking");
#if defined(O_SYNC)
    if (val&O_SYNC)
        printf(",synchronous writes");
#endif
#if !defined(_POSIX_C_SOURCE)&&defined(O_FSYNC)
    if(val&O_FSYNC)
        printf(",synchronous writes");
#endif
    putchar('\n');
    exit(0);
}

这里各标志位均在/usr/include/bits/fcntl里定义。

程序的各种运行结果如下:

$ ./a.out 0 < /dev/tty      //省略了<前面的0
read only

Shell在执行a.out时将它的标准输入重定向到/dev/tty,并且是只读的。argv[1]是0,因此取出文件描述符0(也就是标准输入)的File Status Flag,用掩码O_ACCMODE取出它的读写位,结果是O_RDONLY。注意,Shell的重定向语法不属于程序的命令行参数,这个命行只有两个参数,argv[0]是"./a.out",argv[1]是"0",重定向由Shell解释,在启动程序时已经生效,程序在运行时并不知道标准输入被重定向了。

$ ./a.out 1 > temp.foo    //省略了>前面的1
$ cat temp.foo
write only

Shell在执行a.out时将它的标准输出重定向到文件temp.foo,并且是只写的。程序取出文件描述符1的File Status Flag,发现是只写的,于是打印write only,但是打印不到屏幕上而是打印到temp.foo这个文件中了。

$ ./a.out 2 2>>temp.foo
write only, append

Shell在执行a.out时将它的标准错误输出重定向到文件temp.foo,并且是只写和追加方式。程序取出文件描述符2的File Status Flag,发现是只写和追加方式的。

$ ./a.out 5 5<>temp.foo
read write

Shell在执行a.out时在它的文件描述符5上打开文件temp.foo,并且是可读可写的。程序取出文件描述符5的File Status Flag,发现是可读可写的。
 
十、ioctl函数
 

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

阅读(969) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~