嵌入式 Linux系统编程(一)——文件IO

2019-07-12 15:00发布

嵌入式 Linux系统编程(一)——文件IO

一、文件IO概念

        linux文件IO操作有两套大类的操作方式:不带缓存的文件IO操作,带缓存的文件IO操作。不带缓存的属于直接调用系统调用(system call)的方式,高效完成文件输入输出。它以文件标识符(整型)作为文件唯一性的判断依据。这种操作不是ASCI标准的,与系统有关,移植有一定的问题。而带缓存的是在不带缓存的基础之上封装了一层,维护了一个输入输出缓冲区,使之能跨OS,成为ASCI标准,称为标准IO不带缓存的方式频繁进行用户态 和内核态的切换,高效但是需要程序员自己维护;带缓冲的方式因为有了缓冲区,不是非常高效,但是易于维护。由此,不带缓冲区的通常用于文件设备的操作,而带缓冲区的通常用于普通文件的操作。    文件平时存储在块存储设备中的文件系统中(静态文件),open打开一个文件时,linux内核在进程中建立一个打开文件的数据结构,记录打开的文件的信息;内核在内存中申请建立一段内存,并将静态文件的内容从块存储设备读取到特定地址管理存放(动态文件)。    打开文件后对这个文件的读写操作都是针对内存中的动态文件,当对动态文件进行读写后,动态文件和块存储设备中的静态文件不同步,close时关闭动态文件,内核将内存中的动态文件的内容同步到块存储设备的静态文件。

二、文件描述符

    文件描述符是一个非负整数,用来标识一个进程中打开或创建的文件。当打开一个现有文件或创建一个新文件时,内核向应用程序进程返回一个文件描述符。当读或写一个文件时,使用opencreat返回的文件描述符标识该文件,将其作为参数传递给readwrite等操作函数文件描述符的作用域限于当前应用程序的进程,文件关闭close后,文件描述符将被释放。在遵从POSIX的应用程序中,文件描述符012分别对应STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO,因此一个应用程序进程中文件描述符总是从3开始的。

三、常用文件IO函数

1open

            #include
       #include        #include         int open(const char *pathname, int flags);       int open(const char *pathname, int flags, mode_t mode);Open函数返回打开、创建文件的文件描述符,如果失败返回-1FlagsO_RDONLY   //只读打开O_WRONLY   //只写打开O_RDWR    //读、写打开O_APPEND   //每次写时都追加到文件的尾端O_CREAT   //若此文件不存在,则创建它。使用时,需要第三个参数modeO_EXCL   //如果同时指定了O_CREAT,而文件已经存在,则会出错。用此可以测试一个文件是否存在,如果不存在,则创建此文件O_TRUNC  //如果此文件存在,而且为只写或读写成功打开,则将其长度截短为0O_NONBLOCK  //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次操作和后续的I/O操作设置非阻塞模式。只用于设备文件,不能用于普通文件。O_SYNC    //使每次write都等到物理I/O操作完成,包括由write操作引起的文件属性更新所需的I/OMode使用四个数字指定创建文件的权限,与linux的权限设置相同,如0755 

2close


            #include
       int close(int fd);关闭文件描述符fd指向的动态文件,并存储文件和刷新缓存。 

3read

 #include             ssize_t read(int fd, void *buf, size_t count);Read成功返回读取的字节数,失败返回-1 

4write

         #include          ssize_t write(int fd, const void *buf, size_t count);Write成功返回写入的字节数,失败返回-1 
5、lseek    每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(O_APPEND),则读写位置会指向文件尾。当read()write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。#include        #include         off_t lseek(int fd, off_t offset, int whence);Lseek成功,返回当前的位置,即当前位置距离文件开头的字节数,失败返回-1Offset:偏移量Whence:偏移基址SEEK_SET:将读写位置指向文件头后再增加offset个位移量SEEK_CUR以目前的读写位置往后增加offset个位移量SEEK_END将读写位置指向文件尾后再增加offset个位移量A 欲将读写位置移到文件开头时lseekint fd,0,SEEK_SET);返回0B欲将读写位置移到文件尾时lseekint fd0,SEEK_END);返回文件长度C想要取得目前文件位置时lseekint fd0,SEEK_CUR);返回当前文件指针相对于文件开头的偏移量D、计算文件长度int get_file_length(const char *filename){    unsigned int n = 0;    unsigned int fd = open(filename, O_RDONLY);    if(fd < 0)    {           fprintf(stderr, "error:%s PID: %d ", strerror(errno), getpid());        return -1;     }       n = lseek(fd, 0, SEEK_END);    close(fd);    return n;} E、创建空洞文件int create_null_file(const char *filename, unsigned int len){     unsigned int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);    if(fd < 0)    {           fprintf(stderr, "error:%s PID: %d", strerror(errno), getpid());        return -1;     }       lseek(fd, len, SEEK_SET);    write(fd, "