【APUE】文件IO


不带缓冲的io,绝大多数文件io都只需要用到5个函数open read write lseek close
 
 
  • 文件描述符
是一个非负整数,当打开或者创建一个文件时,内核向进程返回一个文件描述符,使用open或者create返回的文件描述符标识该文件。
按照惯例,标识0,1,2和标准输入输出和标准错误相关联。
 
 
  • open函数
#include<fcntl.h>
open(char* pathname, int oflag, [mode_t mode]);
O_RDONLY  O_WRONLY O_RDWR 三种读写方式必选一种
可选的比较重要的标识
O_APPEND 每次读写都追加到文件的
O_CREAT 若此文件不存在则创建,需要第三个参数以标识新文件的访问权限位
O_EXCL 测试该文件是否存在,若不存在则创建,将测试和创建两个操作合并成一个原子操作
O_TRUNC 若文件存在且以只读或者只写方式打开,就将其长度截断为0
 
 
 
  • lseek函数
每个打开的文件都有一个与其相关的偏移量,是一个非负整数,用以度量从文件开始处计算的字节数。
off_t lseek(int filedes, off_t offset, int whence)
whence:SEEK_SET SEEK_CUR SEEK_END分别表示开始 当前值 和文件末尾
该操作仅将当前文件偏移量记录在内核中,他并不引起任何io操作,用于下一个读写操作。
文件偏移量可以大于文件长度,下一次读写将加长该文件,并且在文件中行程一个空洞,这是被允许的,在文件中但是没有被写过的字节都被读为0
 
#include"apue.h"
#include<fcntl.h>
char buf[] = "input something to the file";
char addbuf[] = "this is my new thing";

int main()
{
    int fd;
    if((fd = creat("test_file", FILE_MODE))<0)
    {
        printf("error\n");
        exit(0);
    }
    int len = sizeof(buf)/sizeof(char);
    if(write(fd, buf, len)!=len)
    {
        printf("error\n");
        exit(0);
    }
    if(lseek(fd, 2*len, SEEK_CUR)==-1)
    {
        printf("error\n");
        exit(0);
    }
    int newlen = sizeof(addbuf)/sizeof(char);
    if(write(fd, addbuf, newlen)!=newlen)
    {
        printf("error\n");
        exit(0);
    }
    return 0;
}

 

 
 
 
  • read函数
从打开的文件中读取内容
read(int filedes, void *buf, size_t nbytes);
若read成功,则返回读到的字节数,若到结尾,则返回0
有很多种可能都会使返回的数值小于需要读的数值。
 
 
  • write函数
向打开的文件中写入数据
ssize_t write(int fieldes, conts void *buf, size_t nbytes);
返回值:若成功则返回写入的字节数,若出错则返回-1
 
#include"apue.h"
#include<fcntl.h>

int main()
{
    char writebuf[] = "i want to write sth in my document!!!!1";
    char readbuf[20];

    int fd;
    if((fd=open("test_file", O_RDWR))==-1)
    {
        printf("error\n");
        exit(-1);
    }
    int readlen = 0;
    int i;
    while(readlen = read(fd, readbuf, 10))
    {
        for(i=0;i<readlen;i++)
        {
            printf("%c", readbuf[i]);
        }
        printf("\n");
        //printf("%s\n", readbuf);
    }
    
    if(lseek(fd, 0, SEEK_END)==-1)
    {
        printf("err\n");
        exit(-1);
    }
    int writelen = strlen(writebuf);
    if(write(fd, writebuf, writelen)!=writelen)
    {
        printf("err\n");
        exit(-1);
    }
    return 0;
}

 

 
 
  • 内核使用三种数据结构表示打开的文件
1)每个进程在进程表中都有一个记录项,记录项中包含有一张打开的文件描述符表,可将其视为一个矢量,与每个文件描述符相关联的是
  • 文件描述符标识
  • 指向一个文件表项的指针
2)内核为左右打开文件维持一张文件表,其中包含
  • 文件状态标识
  • 当前文件偏移量
  • 指向v节点表项的指针
3)每个打开文件或者设备都有一个v结构, 包含了文件类型和对此文件进行各种操作的函数指针。
 
如果两个独立的进程各自打开了同一个文件,则打开该文件的每一个进程都得到一个文件表项,但是对一个给定的文件只有一个v节点表项,每个进程都有自己的文件表项的理由是,这种安排可以使每个进程都有它自己的对该文件的当前偏移量。
 
也可能有多个文件描述符指向同一个文件表项,比如dup和fork
 
 
 
  • 原子操作
是由多步组成的操作,如果该操作原子地执行,要么执行完所有的步骤要么一步也不执行,不可能只执行所有步骤的一个子集
 
扩展:原子性的定位搜索和执行io
ssize_t pread(int fieldes, void *buf, size_t nbytes, off_t offset)
相当于调用lseek和read
ssize_t pread(int fieldes, const void *buf, size_t nbytes, off_t offset)
相当于调用lseek和write
 
和读写文件类似但是有区别:
1.不能中断其定位和读操作
2.不更新文件指针
 
 
  • dup和dup2
int dup(int fieldes);返回一个新的描述符,一定是当前可用描述符中的最小值
int dup2(int fieldes, int fieldes2);指定新的打开的描述符,若已经打开则先将其关闭
返回的新的文件描述符与参数fieldes共享一个文件表项
 
 
 
  • fcntl函数
改变已经打开的文件的性质,或者获取已经打开的文件的性质
int fcntl(int fieldes, int cmd, ...[int arg]);
 
#include"apue.h"
#include<fcntl.h>
int main(int argc, char *argv[])
{
    int val;
    if(argc!=2)
    {
        printf("input file name\n");
        exit(-1);
    }
    if((val=fcntl(atoi(argv[1]), F_GETFL, 0))<0)
    {
        printf("error\n");
        exit(-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:
            printf("error\n");
    }
    if(val & O_APPEND)
        printf(", append");
    if(val & O_NONBLOCK)
        printf(", nonblocking");
    printf("\n");
    return 0;
}

 

 
测试:
./a.out 0 < /dev/tty
./a.out 2 2>>temp.foo
./a.out 5 <>test_file
 
 
posted @ 2012-09-14 13:54  w0w0  阅读(194)  评论(0编辑  收藏  举报