Linx下文件IO

一、文件IO

Linux下一切都是文件。
对于Linux下所有的资源都是文件,Linux给开发者提供了对文件操作的接口,这个接口就是文件IO。
文件IO就是Linux系统提供的对文件操作的接口。API函数接口。

二、关于文件IO

1,系统IO == 》 Linux内核直接提供的对文件操作的接口
2,标准IO == 》标准库提供的对文件操作的接口(在系统IO的基础上进行封装使用)

1、系统IO

==》open close read write lseek
1,open 函数 ==> 打开文件
NAME (函数的简介)
open, openat, creat - open and possibly create a file

SYNOPSIS
#include
#include
#include //open函数头文件

   int open(const char *pathname, int flags);
==> pathname :文件路径名 (字符串类型) 
==> flags	: 标志 (打开文件之后,对文件的操作权限)
O_RDONLY,		//只读
O_WRONLY, 		//只写
or  O_RDWR		//读写
==》返回值:成功返回文件描述符,失败返回-1

文件描述符?  ==》一个正整数。 
打个比方:硬盘:一栋大楼, 文件:大楼里面的房间
操作系统:大楼管理员   open函数:找管理员申请房间钥匙。
文件描述符:对文件操作的钥匙。

例子:使用open打开一个文件 1.txt,打印文件描述符。
Linx下文件IO_第1张图片
为什么返回值都是3?
==》返回值返回的是最小的非负整数。
==》在程序运行过程中,默认打开三个文件,占据三个文件描述符

   0   			   1		   2
标准输入 		标准输出		标准出错

所以,在实际使用中,返回值为3,表示前面的三个已经被占据了。

能不能无限的打开文件? ==》验证一下
==》文件的打开数量是有限的,默认是1024个

==》如果想要不断打开文件,那么在对文件打开之后,不需要的情况下,就把文件描述符关闭。
==》关闭文件描述符 ==》 close

2,close
NAME
close - close a file descriptor

SYNOPSIS
#include

   int close(int fd);			//参数:需要关闭的文件描述符

3,read ==> 从文件中读取数据
NAME
read - read from a file descriptor

SYNOPSIS
   #include 
   ssize_t read(int fd, void *buf, size_t count);
==》fd :需要读取的数据的文件的文件描述符  
==》buf : 存储数据的缓冲区 ==》void * (任意类型指针)
==》count : 想要读取的字节数  --》单位是字节。
返回值:成功返回实际读取的字节数,0代表读取到文件末尾,失败返回-1

==》例子:使用read,读取一个文件的数据。
==》问题:出现乱码 ==》解决方法:读取的时候,缓冲区是64字节,只读取63字节,最后一个字节作为字符串结束标志 ‘\0’

思考:如何把一个大的文件里面的内容全部读取出来?
==》循环读取,循环读取文件,什么时候结束?

==》例子,编写程序,实现cat命令的功能。 ==》用法:cat 文件名
==》循环以文本形式读取文件中的数据,每次读取到数据,都显示在屏幕上。
Linx下文件IO_第2张图片
4,write ==> 写入数据到文件
NAME
write - write to a file descriptor

SYNOPSIS
   #include 
   ssize_t write(int fd, const void *buf, size_t count);
==> fd : 需要写入到的目标文件的文件描述符
==> buf : 需要写入的数据的缓冲区
==> count : 需要写入的字节数  
返回值:成功返回实际写入的字节数,0代表没有数据可写。失败返回-1

==》例子:把一首诗写入1.txt

/*思考:  cp  命令  ==》 拷贝文件 
如何使用文件IO的函数实现cp命令?
==》 cp 1.txt 2.txt   
==> 分别打开1.txt和2.txt,然后循环读取1.txt中的内容,每次读到一片内容,就把这片内容写入到2.txt,如此循环,直到1.txt中的数据被读取完毕,此时拷贝完毕,关闭1.txt,2.txt*/

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    //打印提示信息
    if(argc != 3)
    {
        printf("please input:%s  ",argv[0]);
    }
    //1,打开文件
    int fd0 = open(argv[1],O_RDONLY);
    int fd1 = open(argv[2],O_WRONLY);
    if(-1 == fd0 || -1 == fd1)
    {
        perror("open failed!");
        return -1;
    }
    //2,循环读取1.txt写入2.txt中
    ssize_t ret;
    int buf[64] = {0};
    while(1)
    {
        memset(buf,0,sizeof(buf));//清空buf缓冲区

        ret = read(fd0,buf,sizeof(buf));//ret为读到的字节数
        write(fd1,buf,ret);
        
        if(0 == ret)
        break;
    }
    //关闭文件
    close(fd0);
    close(fd1);
    return 0;
}

==》注意 strlen() 函数功能是计算字符串的长度
==》字符串长度怎么计算?  从第一个字符开始到 ‘\0’字符结束
==》 “hello\0world”  ==> strlen  ==> 5

Cp 命令在拷贝文件时候: cp 源文件名 目标文件名
==》如果目标文件名不存在,cp命令可以创建一个文件,然后实现拷贝

==》能否在打开文件的同时创建文件?
==》 使用open 可以创建文件

   #include 
   #include 
   #include 

   int open(const char *pathname, int flags);		//只能打开文件
   int open(const char *pathname, int flags, mode_t mode);	//可以选择创建文件

	==》 flags == 如果需要创建文件 ==> O_CREAT

例:使用open函数,打开文件1.txt, 如果文件不存在则创建。

Linux下的man中文手册安装步骤:
https://mp.weixin.qq.com/s/N4b8MhoUR2-w9VX_TWoW2A

系统IO — lseek
==> lseek ==> 偏移文件指针 (默认文件读写指针都在文件开头)

NAME
   lseek - reposition read/write file offset		(偏移文件读写指针)

SYNOPSIS
   #include 
   #include 

   off_t lseek(int fd, off_t offset, int whence);
==> fd : 文件描述符
==> offset : 偏移量 ==> 单位字节
==> whence : 从什么地方开始偏移
		SEEK_SET  : 文件开头
		SEEK_CUR : 当前文件指针
		SEEK_END : 文件末尾

==》例:假设文件 1.txt 里面的内容是 helloworld ==> 想要读取第五个字节之后的数据。

==》练习:假设文件1.txt中里面的内容是 helloworld , 设计程序,打开这个文件之后,使用lseek函数把文件读写指针指向文件末尾,然后写入 nihao. (练习时间:20:50 ~ 21:05)


系统IO的一些应用实例:
==》例如:在程序中实现用户信息的注册。
==》strcmp() : 比较两个字符串,用户登录时比较密码是否正确。实现用户登录功能。
==》实现用户注册功能(用户输入用户名+用户密码),我们可以把这信息存储到指定的文件中,在注册功能中,需要使用结构体存储用户名+密码, 再把这个结构体存入文件。

例:实现用户信息的注册功能。

思考:注册的信息如何读取出来?试着实现它。
==》写一个读取用户信息的程序,从 userinfo.txt 中读取用户信息。

2、标准IO

标准IO
由标准库提供的功能函数
标准IO函数: fopen , fclose, fread, fwrite, fseek.
==>fputc, fgets …

1, 标准IO与系统IO之间的关系
Linx下文件IO_第3张图片

 	==> 标准IO调用系统IO实现文件访问,以及IO功能。

2,标准IO的函数
(1)fopen ==> man 3 fopen

   #include 
   FILE *fopen(const char *path, const char *mode);
==> path : 文件路径 (需要的打开的文件路径)
==> mode : 打开之后操作的权限 ==> 字符串
==> “r”  : 只读打开,并且文件流指针指向文件开头
==> “r+” : 读写打开,文件流指针指向文件开头
==> “w” : 如果文件不存在,那就创建文件,只写打开; 如果文件存在,那就先清空文件内容,然后只写打开,文件流指针指向文件开头 
==> “w+” : 如果文件不存在,那就创建文件,读写权限打开,如果文件存在,那就读写权限打开,文件流指针指向文件开头
==> “a” : 以追加的形式打开文件(打开文件之后,文件流指针指向文件末尾),如果文件不存在就创建该文件
==> “a+” : 读写权限打开文件,如果文件不存在就创建,打开之后文件读取的指针指向文件开头,文件写入的指针指向文件末尾。
返回值: FILE * (结构体指针)  ==> 这个结构体在/usr/include/stdio.h里面  文件流指针。
成功返回一个文件流指针,失败返回NULL

==> 在标准IO中,程序运行是默认打开的三个文件流分别是标准输入,标准输出,标准出错
       ==> 标准输入   	   标准输出		  标准出错
标准IO ==> 	stdin			stdout		   stderr
系统IO ==> 	0			       1			2		
            键盘		     显示屏	       显示屏

==》例:使用标准IO,以读写权限打开文件1.txt,如果文件不存在则创建它。

练习:使用fopen,打开文件hello.txt,如果文件不存在就创建它,以追加的形式打开文件。(20:36 ~ 20:46)

(2)fclose ==> 关闭文件流指针

#include 

int fclose(FILE *stream);

(3)fread ==> 从文件流指针中读取文件信息
fwrite ==> 从缓冲地址中写入文件信息

   #include 

   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
   size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
==> ptr : 存储数据的缓冲区,任意类型地址。 
==> size: 读取/写入的数据块的大小,单位字节
==> nmemb : 读取/写入的数据块的数量,
==> stream : 操作的文件流 (文件流指针)
返回值:成功返回实际读取或者写入的数据块的数量,失败返回小于nmemb的值,或者0.
(注意:fread函数在读取到文件末尾或者是读取失败返回值是一样,此时需要使用feof,或者ferror来检测是读取到文件末尾还是读取失败。)

一次读取或者写入的大小 = size * nmemb

==> 例:使用fwrite往文件1.txt中写入50个字节的数据。

==> 例:使用fread从文件中读取数据,一次读取20个字节,循环读取。

练习:在自己的电脑上,使用fread和fwrite 实现对文件的读写操作
1,把一首诗写入到文件 hello.txt
2,把这首诗读取打印出来。

(4) int fseek(FILE *stream, //文件流指针
long offset, //偏移的字节数
int whence); //从哪里开始偏移
SEEK_SET,文件开头 SEEK_CUR, 当前文件指针 or SEEK_END文件末尾

(5)ftell ==> 获取文件指针定位的绝对值(返回文件指针相对于文件开头的偏移量)
long ftell(FILE *stream); //文件流指针

(6)rewind ==> 把文件指针定位到文件开头
void rewind(FILE *stream); //文件流指针
==> 相当于 fseek(fp, 0, SEEK_SET)

标准IO输入输出缓冲区
缓冲区:读取数据/写入数据,数据首先会被放置到缓冲区中,等待条件满足,才会输出内容。
printf() : 标准输出函数,
Linx下文件IO_第4张图片
==> 例如:检测缓冲区的存在。

相关功能函数:
1)fputs
int fputs(const char *s, //输出的字符串
FILE *stream); //文件流指针
==> 把字符串 “helloworld” 输出到标准出错
==> fputs(“helloworld”, stderr);

标准IO常用函数

1,输入函数
#include

   int fgetc(FILE *stream);		//从文件流中获取一次字符
==>例如:从标准输入获取一个字符
==> char ch = fgetc(stdin);

   char *fgets(char *s, int size, FILE *stream);	//从文件中获取一个字符串
==> s : 存放获取的字符串缓冲区
==> size : 获取的字符串的大小
==> stream : 文件流指针
==> 这个函数一般用在什么地方? ==> 用来获取标准输入的字符串
==> scanf(); //标准输入函数,这个函数存在一个缺陷
==> 例如:从键盘获取一个字符串放入buf中
==> scanf(“%s”, buf);  获取字符串放入buf中,在碰到空格时,就会停止,不再获取
==> fgets可以从文件流指针中获取指定数量的字符,

   int getc(FILE *stream);	//从文件流中获取一个字符
   int getchar(void);		//从标准输入中获取一个字符
==> sscanf(),  fscanf();
   int scanf(const char *format, ...);		//从标准输入获取指定格式的数据
   int fscanf(FILE *stream, const char *format, ...);	//从指定的文件流指针中获取指定格式的数据
   int sscanf(const char *str, const char *format, ...);	//从字符串中获取指定格式的内容

==>例:sscanf 获取一个字符串中的整型数。

fscanf(stdin, “%s”, buf) === scanf(“%s”, buf);

2, 输出函数
int fputc(int c, FILE *stream); //把字符c输出到文件流 stream
// 例如: fputc(‘A‘, stdout); ==> printf(“%c”, ‘A’);

   int fputs(const char *s, FILE *stream);	//把字符串输出到文件流 stream中

// 例如: fputs(“hellowrold”, stdout); == printf(“helloworld”);

   int putc(int c, FILE *stream);

   int putchar(int c);	//把字符c输出到标准输出

   int puts(const char *s);	//把字符串s输出到标准输出

==> printf, fprintf, sprintf
int printf(const char *format, …); //标准格式化输出函数
int fprintf(FILE *stream, const char *format, …);//格式化数据输出到指定文件流
int dprintf(int fd, const char *format, …); //格式化数据输出到指定的文件描述符
int sprintf(char *str, const char *format, …); // 把格式化数据输出到指定的内存空间
int snprintf(char *str, size_t size, const char *format, …); //把指定大小的格式化数据输出到指定的内存空间

==> sprintf() ==> 把指定的数据输出的内存中 ==> 实现数据的拼接。

==> 例如:使用sprintf实现字符串的拼接

==> 练习:从键盘输入自己的姓名和年龄, 例如: 张三 18
将输入的姓名和年龄拼接,然后输出。
用两种方法实现: sprintf + strcat

三,文件属性相关函数
1, stat ==> 查看文件详细属性

   #include 
   #include 
   #include 

   int stat(const char *pathname, struct stat *buf);
==> pathname : 文件路径名 
==> buf : 结构体指针,存放文件属性内容
返回值:成功返回0,失败返回-1
       struct stat {
           dev_t     st_dev;         /* ID of device containing file */	文件ID
           ino_t     st_ino;         /* inode number */ 节点号
           mode_t    st_mode;        /* protection */	文件类型
           nlink_t   st_nlink;       /* number of hard links */	文件硬链接
           uid_t     st_uid;         /* user ID of owner */ 文件拥有者用户
           gid_t     st_gid;         /* group ID of owner */ 文件组用户
           dev_t     st_rdev;        /* device ID (if special file) */ 设备ID
           off_t     st_size;        /* total size, in bytes */	文件大小
           blksize_t st_blksize;     /* blocksize for filesystem I/O */ 文件系统块大小
           blkcnt_t  st_blocks;      /* number of 512B blocks allocated */ 文件块的数量

           /* Since Linux 2.6, the kernel supports nanosecond
              precision for the following timestamp fields.
              For the details before Linux 2.6, see NOTES. */

           struct timespec st_atim;  /* time of last access */
           struct timespec st_mtim;  /* time of last modification */
           struct timespec st_ctim;  /* time of last status change */

       #define st_atime st_atim.tv_sec      /* Backward compatibility */
       #define st_mtime st_mtim.tv_sec
       #define st_ctime st_ctim.tv_sec
       };
==> ls -l (该命令可以得到以上结构体信息)

==> 例:使用stat函数查看指定文件的大小。

文件类型查看: ==> st_mode
       S_IFSOCK   0140000   socket		//套接字
       S_IFLNK    0120000   symbolic link	//链接文件
       S_IFREG    0100000   regular file	//普通文件
       S_IFBLK    0060000   block device	//块设备
       S_IFDIR    0040000   directory		//目录文件
       S_IFCHR    0020000   character device	//字符设备
       S_IFIFO    0010000   FIFO		//管道文件
//示例:
if((sb.st_mode &S_IFMT) == S_IFREG)
{
	/*regular file*/
}

2,access 检测文件相关属性是否存在

   #include 
   int access(const char *pathname, int mode);
==> pathname:检测的文件的路径名
==> mode : 检测的权限
R_OK :读权限
W_OK :  写权限
X_OK. 	执行权限
F_OK	是否存在
==> 返回值 : 权限具有则返回0,否则返回-1

==> 例:使用access函数测试文件是否存在

三、目录IO

opendir , readdir, closedir
1, opendir ==> 打开目录文件

   #include 
   #include 

   DIR *opendir(const char *name);
==> name: 需要打开的目录名
==> 返回值 :成功返回一个目录流指针,失败返回 NULL

2, readdir ==> 从目录中读取数据

   #include 

   struct dirent *readdir(DIR *dirp);
==> dirp : 目录流指针  
==> 返回值 struct dirent * 的结构体指针
struct dirent {
           ino_t          d_ino;       /* inode number */	索引号
           off_t          d_off;       /* not an offset; see NOTES */ 从1开始
           unsigned short d_reclen;    /* length of this record */ //目录项的字节数
           unsigned char  d_type;      /* type of file; not supported // 文件类型
                                          by all filesystem types */
           char           d_name[256]; /* filename */	//文件名
       };

==> Linux下,文件名的大小不能超过 255 字节(因为文件名是一个字符串,而字符串要以\0结尾,所以只能有255个字节)

   DT_BLK      This is a block device.		块设备

   DT_CHR      This is a character device.  字符设备

   DT_DIR      This is a directory.		目录文件

   DT_FIFO     This is a named pipe (FIFO).	管道文件

   DT_LNK      This is a symbolic link.	链接文件

   DT_REG      This is a regular file.		普通文件

   DT_SOCK   						套接字文件

3,closedir 关闭目录流指针

   #include 

   #include 

   int closedir(DIR *dirp);

例:使用目录IO函数,对目录进行检索。

思考:在检索目录时,将目录里面所有的文件名输出,假设想要检索特定的文件,例如,检索目录1中的所有 .c 结尾的文件,把文件名输出,如何实现?15:49 ~ 15:54
5分钟, 把想到的实现方案在公屏打出来

==> strcmp

练习:参考readdir.c ,检索指定目录下的所有 .bmp结尾的文件,打印文件名

思考:多级目录检索功能的实现。

四、目录IO Linux下的UI界面编程 --> LCD的使用

1,LCD显示原理
==> lcd也叫做液晶显示屏,液晶屏上存在像素点。像素点上显示不同的颜色数据,组合形成用户看到的图像。

2,6818开发板LCD参数
Linx下文件IO_第5张图片
3,如何使用LCD?
Linux下一切都是文件。 ==> LCD也是一个文件 /dev/fb0
==> 如何对LCD文件进行打开?写入?关闭?

==> 例如:在LCD上显示纯红色图像。

4,Ubuntu下控制LCD显示图像
1)从图形界面进入命令界面
==> ctrl + alt + F2

2)运行程序 sudo ./red
==> 密码:123456 (输入的时候不会回显)

3)从命令界面切换回图形界面
==> ctrl + alt + F7
Linx下文件IO_第6张图片

五、Linux下的UI界面编程 — 图片显示

1,图片显示原理
	将图片文件中的数据读取出来,放在一片内存缓冲区中,然后将缓冲区的内容写入到LCD文件,由此LCD显示图片的内容。

2,图片种类
	常见的图片类型有 bmp, jpg, png, gif ....  (LCD是可以显示任意类型的图片的)
LCD在显示图片的时候,需要将图片中的像素点数据转换成ARGB格式。
1)图片显示的素材,选择bmp格式。
==》bmp被称为原图,bmp图片的像素点数据是不经过压缩的,原封不动的保存在	bmp文件中。
2)关于bmp图片
==> bmp图片文件中的像素点数据都是RGB , ==> 每个像素点都是3字节 

3)准备一张bmp图片。==> 800*480的bmp图片。
==> 准备的bmp图片大小应该是 800*480*3 字节 ==> 1152000字节

Linx下文件IO_第7张图片
==> 图片的实际大小比计算的大小多54字节
==> bmp图片文件中会存在54字节的头信息,在bmp图片的开头会有54字节图片头信 息,不是像素点信息,而是包含了图片标志,图片的宽度,高度等内容。
3,bmp图片特点
1) bmp图片又被称为原图,24位位图,在bmp图片中,每个像素点的内容都是RGB,占3字节
2) 所有的bmp图片都会在文件的开头具有54字节的头信息,在图片的显示过程中,这54字节不需要写入到LCD文件中。

六,显示bmp图片到LCD

将bmp图片文件中的像素点数据读取出来,然后直接写入LCD

出现的问题:
1)图片失真   ==》bmp图片的像素点 RGB,LCD上的像素点 ARGB
2)图片不能填满LCD  ==》bmp图片的大小只有LCD的四分之三
3)图片呈现倒立

==> bmp图片的编解码。

==> 图片失真解决方案:
Bmp图片的RGB ==> ARGB数据

==> 图片呈现倒立
1)图片倒立的原因
==》bmp图片在Windows下的存储,第一个像素点在图片的左下角,而LCD的第一个像素点在LCD的左上角。
将bmp图片的数据,写入到LCD中时,显示的图片与原图关于中间的这条线对称。

Linx下文件IO_第8张图片
==> 图片倒立解决方案
==> 把解码之后的图片数据,里面的像素点数据,交换数据的位置

七,Linux下UI界面编程 – 进阶

Linx下文件IO_第9张图片
1,在LCD上显示任意大小的图片
2,在LCD上任意位置显示任意大小的图片
Linx下文件IO_第10张图片
3,在LCD上居中显示图片 (自行去完成)

八,人机交互模块

1,触摸屏

人与机器的交互,”人”通过输入设备(鼠标,键盘,按键,触摸屏…)给机器输入指令,机器根据人发送的指令去完成相应的工作,通过输出设备(显示屏,音响,LED灯…)将结果反馈给”人”。

2,触摸屏的使用

1,触摸屏的分类

·电容屏 :硬屏,工作原理:在电容屏上存在电子层,当用户手指触摸屏幕时,电子层发生击穿现象,触摸屏驱动采集触摸的位置信息。
·电阻屏 :软屏,

2,触摸屏工作流程
Linx下文件IO_第11张图片
3,GEC6818触摸屏使用
Linx下文件IO_第12张图片

3,输入子系统

==> Linux系统下输入子系统头文件   /usr/include/linux/input.h
                                /usr/include/linux/input-event-codes.h
//输入事件结构体
struct input_event {
	struct timeval time;		//事件发生的时间 (系统时间)
	__u16 type;			//事件的类型	
	__u16 code;			//事件的编码
	__s32 value;			//事件的值
};
Event types:
#define EV_SYN			0x00		//事件分割标志
#define EV_KEY			0x01		//按键事件
#define EV_REL			0x02
#define EV_ABS			0x03		//触摸屏事件

==》思考:点击触摸屏时,位置信息如何描述? ==》通过X-Y坐标系的坐标描述

Event code;
#define ABS_X			0x00		//X轴坐标编码
#define ABS_Y			0x01		//Y轴坐标编码
#define ABS_PRESSURE		0x18 //触摸屏的压力值(手指按下屏幕,压力值为正数,手指弹开,压力值为0)

点击一次屏幕得到的信息。参考ts.c, 在自己的开发板上运行程序,点击一次屏幕观察效果。

type:3, code:0, value:87
type:3, code:1, value:522 ==> 点击屏幕的坐标信息 (87, 522)
type:1, code:330, value:1 //压力值为1,表示手指按下触摸屏
type:0, code:0, value:0 //事件分割
type:1, code:330, value:0 //压力值为0,表示手指离开触摸屏
type:0, code:0, value:0 //事件分割

在6818的触摸屏驱动中,把压力值的选项放在EV_KEY 中的BTN_TOUCH

==> 优化代码: 修改程序,实现只打印点击屏幕的坐标

4,触摸屏应用

·例1:设计一张图片,在LCD上显示这张图片,然后点击图片上的图标,切换到另一张图片,然后结束。
==》1)设计一个图片 800*480的bmp图片
==》2)设计功能代码

实现一个简单的电子相册功能。
功能要求:
1,从指定路径下检索图片文件 --> Pic/
2,可以实现图片的上一张,下一张切换

1)设计功能界面
2)准备相册图片的素材 --> 准备一些bmp图片 (图片大小不要超过680*480)
3)设计功能代码实现相册功能

5,触摸屏滑动判断

1,滑动与点击屏幕的区别
·点击屏幕 : 点击触摸屏可以得到点击屏幕的绝对值坐标
·滑动屏幕 : 在屏幕上滑动时,是相对位置的判断
Linx下文件IO_第13张图片

你可能感兴趣的:(文件IO,嵌入式)