嵌入式 Linux系统编程(一)——文件IO
2019-07-12 15:00发布
生成海报
嵌入式 Linux系统编程(一)——文件IO
一、文件IO概念
linux文件IO操作有两套大类的操作方式:不带缓存的文件IO操作,带缓存的文件IO操作。不带缓存的属于直接调用系统调用(system call)的方式,高效完成文件输入输出。它以文件标识符(整型)作为文件唯一性的判断依据。这种操作不是ASCI标准的,与系统有关,移植有一定的问题。而带缓存的是在不带缓存的基础之上封装了一层,维护了一个输入输出缓冲区,使之能跨OS,成为ASCI标准,称为标准IO库。不带缓存的方式频繁进行用户态 和内核态的切换,高效但是需要程序员自己维护;带缓冲的方式因为有了缓冲区,不是非常高效,但是易于维护。由此,不带缓冲区的通常用于文件设备的操作,而带缓冲区的通常用于普通文件的操作。 文件平时存储在块存储设备中的文件系统中(静态文件),open打开一个文件时,linux内核在进程中建立一个打开文件的数据结构,记录打开的文件的信息;内核在内存中申请建立一段内存,并将静态文件的内容从块存储设备读取到特定地址管理存放(动态文件)。 打开文件后对这个文件的读写操作都是针对内存中的动态文件,当对动态文件进行读写后,动态文件和块存储设备中的静态文件不同步,close时关闭动态文件,内核将内存中的动态文件的内容同步到块存储设备的静态文件。二、文件描述符
文件描述符是一个非负整数,用来标识一个进程中打开或创建的文件。当打开一个现有文件或创建一个新文件时,内核向应用程序进程返回一个文件描述符。当读或写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传递给read或write等操作函数。文件描述符的作用域限于当前应用程序的进程,文件关闭close后,文件描述符将被释放。在遵从POSIX的应用程序中,文件描述符0、1、2分别对应STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,因此一个应用程序进程中文件描述符总是从3开始的。三、常用文件IO函数
1、open
#include #include #include int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);Open函数返回打开、创建文件的文件描述符,如果失败返回-1。Flags:O_RDONLY //只读打开O_WRONLY //只写打开O_RDWR //读、写打开O_APPEND //每次写时都追加到文件的尾端O_CREAT //若此文件不存在,则创建它。使用时,需要第三个参数modeO_EXCL //如果同时指定了O_CREAT,而文件已经存在,则会出错。用此可以测试一个文件是否存在,如果不存在,则创建此文件。O_TRUNC //如果此文件存在,而且为只写或读写成功打开,则将其长度截短为0。O_NONBLOCK //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次操作和后续的I/O操作设置非阻塞模式。只用于设备文件,不能用于普通文件。O_SYNC //使每次write都等到物理I/O操作完成,包括由write操作引起的文件属性更新所需的I/O。Mode:使用四个数字指定创建文件的权限,与linux的权限设置相同,如0755 2、close
#include int close(int fd);关闭文件描述符fd指向的动态文件,并存储文件和刷新缓存。 3、read
#include ssize_t read(int fd, void *buf, size_t count);Read成功返回读取的字节数,失败返回-1 4、write
#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、 欲将读写位置移到文件开头时lseek(int fd,0,SEEK_SET);返回0B、欲将读写位置移到文件尾时lseek(int fd,0,SEEK_END);返回文件长度C、想要取得目前文件位置时lseek(int fd,0,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, "
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮