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

嵌入式 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#includeint 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#includessize_t read(int fd, void *buf, size_t count);Read成功返回读取的字节数,失败返回-1

4、write#includessize_t write(int fd, const void *buf, size_t count);Write成功返回写入的字节数,失败返回-1。5、lseek每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。当read()或write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。#include#includeoff_t lseek(int fd, off_t offset, int whence);Lseek成功,返回当前的位置,即当前位置距离文件开头的字节数,失败返回-1Offset:偏移量Whence:偏移基址SEEK_SET:将读写位置指向文件头后再增加offset个位移量SEEK_CUR:以目前的读写位置往后增加offset个位移量SEEK_END:将读写位置指向文件尾后再增加offset个位移量A、欲将读写位置移到文件开头时lseek(intfd,0,SEEK_SET);返回0B、欲将读写位置移到文件尾时lseek(intfd,0,SEEK_END);返回文件长度C、想要取得目前文件位置时lseek(intfd,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, " ",1);close(fd);return 0;}

四、错误信息errno就是error number。如果程序代码中包含 #include,函数调用失败的时候,系统会自动用用错误代码填充errno这个全局变量,取读errno全局变量可以获得失败原因。函数调用失败是否会设置errno全局变量由函数决定,并不是所有函数调用失败都会设置errno变量。#includechar *strerror(int errnum);fprintf(stderr,"error:%s, PID:%d ",strerror(errno),getpid());根据errnum错误码返回一个指向描述errnum错误码信息的字符串指针。#includevoid perror(const char *s);perror ( )用来将上一个函数发生错误的原因输出到标准错误(stderr),参数s所指的字符串会先打印出,后面再加上错误原因 字符串。

五、文件共享文件共享的是三种实现方式:1、同一个进程中多次打开同一个文件2、不同进程中多次打开同一个文件3、Dup和dup2让进程复制文件描述符同一个进程中多次打开同一个文件,返回的文件描述符不同,同时对这个文件进行写操作时,分别写入内容,后边写入的内容将覆盖前边写入的内容,此时不同的文件描述符拥有自己的文件指针。当open创建、打开文件时采用O_APPEND,则不同的文件描述符的不同文件指针会实现同步。O_APPEND是原子操作的。所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断。文件描述符的复制#includeint dup(int oldfd);//返回新分配的文件描述符,失败返回-1int dup2(int oldfd, int newfd);//newfd为指定的新的文件描述符,返回新分配的文件描述符,失败返回-1dup函数复制的文件描述符不同,但文件指针相同,所以对文件的操作是原子操作的。

六、文件IO与标准IO库的区别文件IO与标准IO库的区别:文件IO是linux系统的API,标准IO库是C语言库函数,标准IO库函数由linux API封装而来,函数内部通过调用linux API完成。API在不同的操作系统之间不能通用,C语言库函数可以在不同操作系统之间移植。文件IO函数不带缓存,标准IO库函数带缓存。

本文出自 “生命不息,奋斗不止” 博客,转载请与作者联系!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值