I/O操作


一、基本I/O操作(基于文件描述符的不带缓存的低级I/O操作)

Linux的输入/输出操作,通常为5个方面:
    打开(open),读取(read),写入(write),定位(lseek),关闭(close)
    文件描述符(file descriptor):
        一个非负的整数,它是一个索引值,并指向内核中每个进程打开文件的记录表。
1、open函数
    函数原型:

        int open(char * pathname, int flags)
        int open(char * pathname, int flags, mode_t mode)

    
    pathname: 表示被打开的文件名称,可以包含路径
    flags: 为一个或多个标志,表示文件的打开方式
    mode: 被打开文件采取的权限模式
    函数返回值:成功则返回文件描述符,出错返回-1
    
    flags:(falgs参数可通过“|”组合构成,只读、只写、读写 这三种方式是互斥的,不可同时使用)
        O_RDONLY(只读方式打开),
        O_WRONLY(只写方式打开),
        O_RDWR(读/写方式打开),
        O_CREAT(如果文件不存在,就创建新的文件),
        O_EXCL(如果使用O_CREAT时,文件存在,则可返回错误信息),
        O_TRUNC(如果文件已存在,且以只读或只写方式打开,则先删除文件中的原有数据),
        O_APPEND(以添加方式打开文件,在打开文件的同时,文件指针指向文件末尾)
        
    为了防止对文件的意外操作,往往要以合适的方式打开文件(只读,只写),每个文件只负责一个特定的用
    途,有利于提高这些文件的重复利用。    
    
    mode:
        S_IRWXU | 00700 (属主用户读写和执行权限)
        S_IRUSR | 00400 (属主用户读权限)
        S_IWUSR | 00200 (属主用户写权限)
        S_IXUSR | 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 (其他用户执行权限)
        
2、read和write函数
    read和write函数原型:

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

        
    fd: 文件描述符
    buf: 指定存储器读出/写入数据的缓冲区
    count:指定读出或写入的字节数
    函数返回值:
        发生错误,返回-1,同时设置errno变量为错误代码。
        操作成功,则返回值是实际读取或写入的字节数,这个字节数可能小于要求的字节数count,对于读
        操作——所剩字节数少于count时,出现这种情况;写操作——磁盘已满或其它问题时出现这种情况。
    
    在使用这两个函数时应该尽量采取块读/写的方式,提高I/O的效率

3、close函数(close会让缓冲区中的数据写回磁盘,并释放文件所占用的资源)
    close函数原型:

        int close(int fd)

    
    fd:文件描述符
    函数返回值:文件顺利关闭,返回0;发生错误返回-1,并置errno。
        
    示例:
        

        #include <unistd.h>
        #include <sys/stat.h>
        #include <sys/types.h>
        #include <fcntl.h>
        #include <stdio.h>
        int main(void){
            int fd,size;//fd:文件描述符,用于判断打开|新建文件是否成功,size:读取到的字节数
            char s[] = "hello";//需要写入的字符串
            char buffer[80];//存储读出数据的缓冲区
            
            fd = open("test.txt", O_WRONLY | O_CREAT);//以只写方式打开文件,若不存在则创建文件
            if (fd == -1){
                printf("Open or create file failed.\n");
                return -1;
            }
            write(fd, s, sizeof(s));//像该文件写入字符串
            close(fd);
            
            fd = open("test.txt", O_RDONLY);//以只读方式打开文件
            if (fd == -1){
                printf("Open file failed.\n");
                return -1;
            }
            size = read(fd, buffer, sizeof(buffer));//读取文件内容到buffer并返回读取的字符个数
            close(fd);
            printf("%s", buffer);
            return 0;
        }

        
二、基于流缓冲的标准I/O操作        
    1、fopen函数
    打开文件有三个标准函数:

        FILE * fopen(const char * pathname, const char * type)
        FILE * freopen(const char * pathname, const char * type, FILE * fp)
        FILE * fdopen(int filedes, const char * type)

        
    它们以不同的模式打开文件,并返回一个指向文件流的FILE指针,此后对文件读/写都是通过这个FILE指针来
    进行的。以下仅介绍fopen函数。
        
    mode:(mode字符串中带有b字符的表示打开的文件是二进制的文件)
        R/rb:打开只读文件(该文件必须存在)
        R+/r+b:打开可读/写的文件(该文件必须存在)
        W/wb:打开只写文件,若该文件存在,则长度清为0,否则建立该文件
        w+/w+b:打开可读/写文件,若该文件存在,则长度清为0,否则建立该文件
        a/ab:以追加的方式打开可读/写文件,若文件存在,则在文件尾部追加数据,不修改文件原有数据,
            否则新建文件。
        a+/a+b:以追加的方式打开只写文件,若文件存在,则在文件尾部追加数据,不修改文件原有
            数据,否则新建文件。
        
    fopen函数可以指定打开文件的路径和模式,fdopen函数会将参数fd的文件描述符转换为对应的文件制针后返
    回。freopen函数会将已打开的文件stream关闭后,打开参数path的文件。    
    
    2、fclose函数(将缓冲区的数据写入文件并释放系统所提供的文件资源)

        int fclose(FILE * fp)

        
        仅将缓冲区的数据写入文件可使用fflush函数:int fflush(FILE * fp)
        
    3、fread和fwrite函数

        size_t fread(void * ptr, size_t size, size_t nmemb, FILE * stream)
        size_t write(const *ptr, size_t size, size_t nmemb, FILE * stream)

    
        size: 一条记录的长度
        nmemb: 指出要读或写多少条记录
        返回值:读或写的记录数,成功时返回的记录数等于nmemb,出错或读到文件末尾时返回的记录数
                小于nmemb也可能返回0.
            
        这里读写的记录是指一串固定长度的字节,如一个int、一个结构体...
        fread从文件stream中读取size * nmemb 字节保存到ptr中,
        fwrite把ptr中的size * nmemb 字节写到文件stream中。
        
        示例:
          

            struct record{
                char name[10];
                int age;
            }
            
            写入数据:write.c
            struct record array[2] = { {"Tobey",20},{"Ack",23} };
            FILE *fp = fopen("recfile",w);//以只写方式打开文件,若文件不存在则创建文件
            if(fp == NULL){
                ...
            }
            fwrite(array, sizeof(struct record), 2, fp);//将array中的数据写入fp
            fclose(fp);
            
            读出数据:read.c
            stuct record array[2];
            FILE *fp = fopen("recfile",r);//以只读方式打开文件,文件必须存在
            if(fp == NULL){
                ...
            }
            fread(array,sizeof(struct record), 2, fp);
            printf("Name1: %s\tAge1: %d\n",array[0].name,array[0].age);
            fclose(fp);