赞
踩
一、linux IO编程学习大纲。
1、文件IO概念、文件概念、文件类型。
2、系统IO --> 如何使用系统IO接口访问/写入/读取/关闭文件。
3、系统IO文件描述符的概念?文件描述符与文件的关系?研究文件描述符的值。
4、文件偏移量。
5、系统IO应用实例:lcd液晶设备、触摸屏。
6、系统IO另外一个处理lcd液晶设备方式:内存映射。
7、标准IO --> 如何使用标准IO接口访问/写入/读取/关闭文件。
8、标准IO --> 一系列处理字符/字符串函数。
9、标准IO应用实例:显示bmp格式图片。
10、目录IO --> 访问目录、切换工作路径、读取目录、关闭目录。
11、将文件知识点逐渐地加入小孩的项目中。
二、文件IO概念。
1、什么是文件?
在linux下,一切都是文件。
普通文件: 图片、视频、音乐、压缩包、PPT...
设备文件: led灯、蜂鸣器、lcd液晶设备、触摸屏..
结论:除了我们常见的文件是文件之外,linux系统还会把硬件设备当做是文件,所以在linux眼中,所有的东西都是文件。
2、什么是IO?
IO ---> input/output --> 输入输出
文件IO ---> 对文件输入/输出 --> 写入数据到文件/从文件中读取数据出来
3、如何实现文件读取/写入?
不需要用户自己写自定义函数,因为在linux下,已经有现成的函数来实现。
访问文件方式有两种:
系统IO ---> 系统调用 ---> 第2手册 System calls (functions provided by the kernel)
标准IO ---> 库调用 ---> 第3手册 Library calls (functions within program libraries)
4、什么时候使用系统IO?什么时候使用标准IO?
当你访问设备文件(led灯、触摸屏、蜂鸣器...)时,就是使用系统IO接口来访问的。
例如:写了一个温湿度传感器驱动 --> 那么就使用系统IO接口来访问温湿度传感器。
当你访问普通文件(图片、文本文档..)时,就是使用标准IO接口来访问。
例如:你想打开test.txt这个文件 --> 那么就使用标准IO接口来访问这个文件。
5、文件类型。 --> 7种
'-' 普通文件 ---> 标准IO
'd' 目录文件 ---> 目录IO
'l' 链接文件
'p' 管道文件 ---> 系统IO
's' 套接字文件 ---> 有一套独特的方式来访问
'c' 字符设备文件 ---> 系统IO
'b' 块设备文件 ---> 系统IO
三、如何使用系统IO接口来处理文件?
1、如何打开文件? ---> open() ---> man 2 open
//头文件 --> 只要工程中使用了open函数,就一定要包含以下三个头文件。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//函数原型
int open(const char *pathname, int flags);
参数:
pathname: 需要打开的那个文件的路径。
flags: 操作文件的权限。(三个必须选一个)
O_RDONLY, O_WRONLY, or O_RDWR
只读 只写 可读可写
返回值:
成功: new file descriptor 新的文件描述符 (最小,非负,没有使用过的数字)
失败: -1
思考题:open函数什么时候会打开失败?
1)你访问的文件不存在。
2)如果文件本身权限不允许的,那么操作权限不对,也会失败。
例如: 某一个文件本身权限"-wx-wx-wx",如果使用O_RDONLY/O_RDWR去打开文件,那么就会失败。
2、如何关闭文件? ---> close() --> man 2 close
//头文件 --> 只要工程中使用了close函数,就一定要包含以下头文件
#include <unistd.h>
//函数原型
int close(int fd);
参数:
fd: 需要关闭的那个文件的文件描述符。
返回值:
成功:0
失败:-1
例子: 假设家目录下有一个文件名字叫ggg.txt,现在要求写一个程序去打开该文件:
如果打开成功,则输出open ggg.txt success! 如果打开失败,则输出open ggg.txt error!
接下来,就关闭该文件。
如果关闭成功,则输出close ggg.txt success!如果关闭失败,则输出close ggg.txt error!
#include <stdio.h> //for printf
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
int main(int argc,char *argv[])
{
//1. 打开ggg.txt文件
int fd;
fd = open("ggg.txt",O_RDWR);
if(fd >= 0)
{
printf("open ggg.txt success!\n");
}
else{
printf("open ggg.txt error!\n");
}
//2. 关闭ggg.txt文件
int ret;
ret = close(fd);
if(ret == 0)
{
printf("close ggg.txt success!\n");
}
else{
printf("close ggg.txt error!\n");
}
return 0;
}
练习1: 看看文件描述符等于多少? //3
练习2: 在开发板的根目录下dev目录下,有一个文件叫fb0,现在要求写一个程序去打开该文件:
如果打开成功,则输出open fb0 success! 如果打开失败,则输出open fb0 error!
接下来,就关闭该文件。
如果关闭成功,则输出close fb0 success!如果关闭失败,则输出close fb0 error!
核心代码:
fd = open("/dev/fb0",O_RDWR);
代码需要交叉编译:
arm-linux-gcc xxx.c -o xxx
四、文件描述符?
1、什么是文件描述符?
文件描述符其实就是open函数的返回值,当open函数执行成功之后,就会返回一个非负的,最小的,没有使用过的整数。
例如:
3 = open("1.txt"); //在后面的代码中,3就是代表1.txt这个文件
4 = open("2.txt"); //在后面的代码中,4就是代表2.txt这个文件
A105 = open("关国源");
结论:将来需要处理某一个文件时候,我们不需要提供文件的名字,只需要提供文件对应的文件描述符就可以了。
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("标准输入");
1 = open("标准输出");
2 = open("标准出错");
3、验证文件描述符特性: 非负,最小,没有使用过的整数。
假设当前目录下: a.txt b.txt c.txt d.txt
open("a.txt");
open("b.txt");
open("c.txt");
close("b.txt");
open("d.txt");
close("a.txt");
close("c.txt");
open("a.txt"); 3
open("c.txt"); 5
close("d.txt");
请问这时候open("d.txt")返回值是多少? -> 4
结论:
打开一个文件,得到一个文件描述符 (申请资源)
关闭一个文件,这个文件对应的文件描述符就会释放,然后别人就可以占用。 (释放资源)
4、研究文件描述符的最大值是多少?
#include <stdio.h> //for printf
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
int main(int argc,char *argv[])
{
int fd;
while(1)
{
fd = open("ggg.txt",O_RDWR);
printf("fd = %d\n",fd);
if(fd == -1)
{
break;
}
}
return 0;
}
最大值:1023
有效文件描述符值有1024个。
五、open函数的拓展参数。
int open(const char *pathname, int flags, mode_t mode);
pathname:文件路径
flags:
必选(三选一)
O_RDONLY -> 只读
O_WRONLY -> 只写
O_RDWR -> 可读可写
可选(0个/多个) --> 如果选了多个,则每一个标志之间使用"|"连接起来。
O_APPEND --> 以追加的方式来打开文件,在每一次写操作之前,文件的定位都是在文件的末尾。
O_CREAT --> 如果想打开的那个文件不存在,则文件就会创建。
--> mode参数就是那个新文件的起始权限。
mode: 填八进制权限 例如:0666
O_TRUNC --> 如果文件存在,则清空该文件。
例子:验证O_TRUNC参数是可以清空文件的。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
int main(int argc,char *argv[])
{
int fd;
fd = open("ggg.txt",O_WRONLY|O_TRUNC);
close(fd);
return 0;
}
练习3: 尝试在家目录下创建一个新的文件叫ggy.txt,并给0666的权限。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
int main(int argc,char *argv[])
{
int fd = open("/home/gec/ggy.txt",O_RDWR|O_CREAT,0666);
if(fd < 0)
{
printf("open ggy.txt error!\n");
}
else{
printf("open ggy.txt success!\n");
}
close(fd);
return 0;
}
结论:一般设计文件权限的问题时候,都会先将umask设置为0,那么这样做好处是:你设置多少,结果就是多少。
六、文件数据输出/输入。
1、如何读取文件的数据? --> read() --> man 2 read
功能: read from a file descriptor
//从文件描述符中读取数据出来
//头文件
#include <unistd.h>
//函数原型
ssize_t read(int fd, void *buf, size_t count);
参数:
fd:文件描述符
buf:数据缓冲区
count:尝试读取的字节数 (愿望值)
返回值:
成功:已经读取到的字节数
失败:-1
例子: 尝试从文本文件中读取数据出来。
注意: 从文本文件中读取出来的内容都是以字符串的形式存在。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
int main(int argc,char *argv[])
{
//1. 打开ggg.txt
int fd = open("ggg.txt",O_RDWR);
if(fd < 0)
{
printf("open ggg.txt error!\n");
}
//2. 尝试读取文件的内容出来
char buf[100] = {0};
int n;
n = read(fd,buf,sizeof(buf));
printf("n = %d\n",n);
printf("buf = %s\n",buf);
//3. 关闭文件
close(fd);
return 0;
}
-------------------------------------
运行结果:
文件内容: yueqian
gec@ubuntu:/mnt/hgfs/GZ2180/07 linux IO编程/01/code$ ./demo3
n = 7
buf = yueqian
练习4: 重复读取一个文件,那么第二次读取的时候是在第一次基础上继续读,还是从文件开头读取?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
//1. 打开ggg.txt
int fd = open("ggg.txt",O_RDWR);
if(fd < 0)
{
printf("open ggg.txt error!\n");
}
//2. 尝试读取文件的内容出来
//yueqianappletreehelloworld
char buf[100] = {0};
int n;
n = read(fd,buf,10);
printf("n = %d\n",n); //10
printf("buf = %s\n",buf); //yueqianapp
bzero(buf,sizeof(buf));
n = read(fd,buf,10);
printf("n = %d\n",n); //10
printf("buf = %s\n",buf); //letreehell --> 说明是继续读取
//yueqianapp --> 说明是重新读取
//3. 关闭文件
close(fd);
return 0;
}
答案: 继续读取。
2、写入数据到文件中。 --> write() --> man 2 write
功能: write to a file descriptor
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
fd: 文件描述符
buf: 数据缓冲区
count: 写入的字节数
返回值:
成功: 写入的字节数
失败: -1
例子: 尝试写入一些数据到一个空白的文件中。
------------------------------------------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
int fd = open("kkk.txt",O_RDWR); //文件定位在开头
if(fd < 0)
{
printf("open kkk.txt error!\n");
}
char buf[10] = "hello";
int n = write(fd,buf,5);
printf("n = %d\n",n);
close(fd);
return 0;
}
运行之前:
文件: 空白
运行之后:
n = 5
文件: hello
----------------------------------------------------------
如果不是空白文件,则会重头覆盖文件的内容。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
int fd = open("kkk.txt",O_RDWR); //文件定位在开头
if(fd < 0)
{
printf("open kkk.txt error!\n");
}
char buf[10] = "apple";
int n = write(fd,buf,5);
printf("n = %d\n",n);
close(fd);
return 0;
}
运行之前:
文件: hello
运行之后:
n = 5
文件: apple
-------------------------------------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
int fd = open("kkk.txt",O_RDWR|O_APPEND); //文件定位在末尾
if(fd < 0)
{
printf("open kkk.txt error!\n");
}
char buf[10] = "apple";
int n = write(fd,buf,5);
printf("n = %d\n",n);
close(fd);
return 0;
}
运行之前:
文件: hello
运行之后:
n = 5
文件: helloapple
------------------------------------------------------
七、研究read/write函数的返回值。
--------------------------------------read函数返回值-----------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
//文件内容:helloworld
int fd = open("qqq.txt",O_RDWR);
char buf[100] = {0};
/*
int n = read(fd,buf,100);
printf("n = %d\n",n); //10
printf("buf = %s\n",buf); //helloworld
*/
/*
int n = read(fd,buf,20);
printf("n = %d\n",n); //10
printf("buf = %s\n",buf); //helloworld
*/
/*
int n = read(fd,buf,10);
printf("n = %d\n",n); //10
printf("buf = %s\n",buf); //helloworld
*/
/*
int n = read(fd,buf,5);
printf("n = %d\n",n); //5
printf("buf = %s\n",buf); //hello
*/
close(fd);
return 0;
}
-------------------------------------------write函数返回值----------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //for open
#include <unistd.h> //for close
#include <strings.h>
int main(int argc,char *argv[])
{
//文件: 空白
int fd = open("xxx.txt",O_RDWR|O_TRUNC);
char buf[11] = "helloworld";
/*
int n = write(fd,buf,5);
printf("n = %d\n",n); //5 文件的内容:hello
*/
/*
int n = write(fd,buf,8);
printf("n = %d\n",n); //8 文件的内容: hellowor
*/
/*
int n = write(fd,buf,10);
printf("n = %d\n",n); //10 文件的内容: helloworld
*/
/*
int n = write(fd,buf,11);
printf("n = %d\n",n); //11 文件的内容:helloworld + \0
*/
int n = write(fd,buf,100);
printf("n = %d\n",n); // 100 文件的内容:helloworld + \0 + 89个乱码
close(fd);
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。