一、文件IO学习大纲。 1、文件IO概念、文件概念、文件类型。 2、访问文件方法一 -> 系统IO 打开?/读取?/写入?/关闭? 3、系统IO文件描述符概念?文件描述符与文件的关系?文件描述符的值。 4、文件偏移量概念。 5、系统IO应用实例:LCD液晶、触摸屏。 6、系统IO另外一种访问文件的方式:内存映射。 -> 针对LCD液晶 7、访问文件方法二 -> 标准IO 打开?/读取?/写入?/关闭? 8、标准IO函数:处理字符/字符串 9、目录IO:访问目录,切换目录,读取目录,关闭目录。
二、文件IO概念? 1、什么是文件? 在linux下,一切都是文件。 除了我们平时常见的文件:1.txt/2.jpg/3.bmp/4.mp3是文件之外,linux系统还会把硬件设备当作是文件,例如:LED灯、触摸屏、LCD液晶屏幕,蜂鸣器,ADC,这些硬件设备在linux的眼中,都是文件来的。
2、什么是IO? IO -> input/output -> 输入/输出 文件IO -> 对文件数据输入/输出 -> 写入数据到文件/从文件中读取数据出来。
3、如何实现文件读取/写入? 不需要用户写自定义函数,因为在linux下,已经有现成的函数来实现。
访问文件方式有两种: 系统IO -> 系统调用 -> 2 System calls -> 系统IO接口都是在第2手册。 标准IO -> 库调用 -> 3 Library calls -> 标准IO接口都是在第3手册。 4、使用系统IO与标准IO访问有什么区别? 系统IO来处理文件,没有缓冲区,直接按字节来处理。 标准IO来处理文件,有缓冲区,按块来处理。
作用对象: 访问硬件设备文件时(LED灯、触摸屏、LCD液晶) -> 直接使用系统IO来处理。 例如: 写一个温湿度传感器驱动 -> 使用系统IO来访问温湿度传感器驱动
访问普通文件(1.txt/2.bmp/3.jpg/4.mp3) -> 标准IO来处理。 例如:访问test.txt这个文件 -> 使用标准IO来访问。
5、文件类型。 -> 7种。 '-' 普通文件 -> 标准IO 'd' 目录文件 -> 目录IO 'l' 链接文件 'p' 管道文件 -> 系统IO 's' 套接字文件 'c' 字符设备文件 -> 系统IO 'b' 块设备文件 -> 系统IO
三、如何使用系统IO访问文件? 1、如何打开文件? -> open() -> man 2 open 函数功能:open and possibly create a file //打开和创建文件。
头文件: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
函数原型: int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
参数: pathname:需要打开的那个文件的路径名。 (绝对路径/相对路径) flags: O_RDONLY:只读 O_WRONLY:只写 O_RDWR:可读可写
返回值: 成功:新的文件描述符file descriptor(其实就是一个最小,非负整数,没有使用过的) 失败:-1
注意:open函数什么时候会打开失败? 1)你打开的路径不存在时。 2)如果文件本身的权限不允许,那么操作权限不对,也会失败。 例如: 文件本身的权限: "-wx-wx-wx",如果以O_RDONLY/O_RDWR去打开文件,那么就会失败。
2、如何关闭文件? -> close() -> man 2 close 函数功能:close a file descriptor //关闭掉一个文件描述符
头文件: #include <unistd.h>
函数原型: int close(int fd);
参数: fd:需要关闭的那个文件的文件描述符。
返回值: 成功:0 失败:-1
练习1: 写程序,访问家目录下test.txt,如果访问成功,则输出"open file success",否则输出"open file error",并关闭文件,如果关闭成功,则输出"close file success",否则输出"close file error"。
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
int main(int argc,char *argv[]) { int fd,ret; fd = open("/home/gec/test.txt",O_RDWR); if(fd >= 0) { printf("open file suceess!\n"); } else{ printf("open file error!\n"); } printf("fd = %d\n",fd); ret = close(fd); if(ret == 0) { printf("close file success!\n"); } else{ printf("close file error!\n"); } return 0; }
练习2: 看看访问之后的那个文件的文件描述符是多少? -> 3 练习3: 尝试访问一下开发板中/dev/fb0这个文件,访问之后就关闭它。 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
int main(int argc,char *argv[]) { int fd; fd = open("/dev/fb0",O_RDWR); if(fd < 0) { printf("open file error!\n"); } close(fd); return 0; }
四、文件描述符? 1、什么是文件描述符? 文件描述符是open函数的返回值,当open()执行成功时,就会返回非负,最小,没有使用过的整数。 例如: 3=open("1.txt"); //3就是代表这个1.txt这个文件。 4=open("2.txt"); //4就是代表这个2.txt这个文件。 A105=open("关国源") //A105就是代表这个关国源这个文件。
结论:将来需要处理文件时,我们不需要提供文件名字,只需要提供文件对应的文件描述符就可以。
2、访问文件时,发送fd从3开始分配,说明0/1/2已经被占用,究竟是谁在占用? 其实在系统启动时,就会默认打开3个文件,分别是"标准输入","标准输出","标准出错",他们其实是一个宏定义来的,是被定义在一个头文件中,头文件路径:/usr/include/unistd.h
/* Standard file descriptors. */ #define STDIN_FILENO 0 //标准输入 -> 对象:键盘 #define STDOUT_FILENO 1 //标准输出 -> 对象:屏幕 #define STDERR_FILENO 2 //标准出错 -> 对象:屏幕
可以理解: 只要系统启动, 0 = open("标准输入")
3、举例子。 假设当前目录下有:a.txt b.txt c.txt d.txt 打开a.txt 打开b.txt 打开c.txt 关闭b.txt 打开d.txt 关闭a.txt 关闭c.txt 打开a.txt 打开c.txt 关闭d.txt 打开d.txt -> 返回值是多少? --> 4
结论:打开一个文件时候,就会得到一个文件描述符。 -> 申请资源 关闭一个文件时候,这个文件对应的文件描述符就可以被别人使用。-> 释放资源
4、研究文件描述符有没有最大值? #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int main(int argc,char *argv[]) { int fd; while(1) { fd = open("./a.txt",O_RDWR); printf("fd = %d\n",fd); if(fd == -1) { break; } } return 0; }
范围:0~1023。 记住:打开文件之后,记得要关闭!
五、open函数的拓展参数。
int open(const char *pathname, int flags, mode_t mode);
pathname:需要打开的文件的路径 flags: 必选(三选一) O_RDONLY:只读 O_WRONLY:只写 O_RDWR:可读可写
可选(0个/多个) -> 如果选了,就是使用了位或"|"来添加。 O_APPEND:以追加的方式打开文件,在每一次写数据之前,文件的定位都是在末尾。 O_CREAT:如果文件不存在,就会创建。 如果flags中有O_CREAT,那么mode这个参数就一定要填。 如果flags中没有O_CREAT,那么mode这个参数就算你填了,也没用。 O_TRUNC:如果文件存在并且是一个普通文件,而且打开方式必须是O_RDWR/O_WRONLY,那么这个文件就会被清空。
例子1:测试O_CREAT是否能创建文件。
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
int main(int argc,char *argv[]) { umask(0000); int fd; fd = open("/home/gec/ggy_test.txt",O_RDWR|O_CREAT,0777); if(fd < 0) { printf("open error!\n"); } close(fd); return 0; }
如果文件是存在的: O_CREAT -> 不创建,打开成功 O_CREAT|O_EXCL -> 不创建,打开失败 O_EXCL就是要确保O_CREAT这个参数创建了才会生效!
如果文件是不存在的: O_CREAT -> 创建文件并且打开成功 O_CREAT|O_EXCL -> 创建文件并且打开成功
例子2: 测试O_TRUNC能不能清空?
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
int main(int argc,char *argv[]) { umask(0000); int fd; fd = open("./a.txt",O_RDWR|O_TRUNC); if(fd < 0) { printf("open error!\n"); } close(fd); return 0; }
一般地,O_CREAT|O_TRUNC 连用,会有什么效果? 100%确保运行之后文件是存在的,并且是空白的!