中文字库的原理与应用
⦁ 基本概念
一般在项目中都会显示汉字,都采用中文简体字符集,计算机早期只有ANSI组织设计的ANSII码,其实也属于字符集,这套字符集并未收录中文,只收录256个字符。 所以后期中国国家标准总局设计了一套中文字符集叫做GB2312中文简体字符集。
⦁ 汉字结构
⦁ 字库生成
在嵌入式开发中一般都会使用LCD屏或者OLED屏进行汉字显示,所以都需要使用汉字库或者使用取模软件生成汉字的字模,一般都是采用点阵字库。
注意:GB2312汉字库的汉字的具体位置和汉字本身大小是无关的,汉字的区码和位码来定位汉字在库的位置,一个汉字的占用字节的大小和汉字本身的分辨率 ,比如1616大小的一个汉字,需要占用32字节。如果生成的是1616的汉字库,则库中每个单元都是32字节。
⦁ 调用字库
其实在linux系统和windows都是存储了汉字库,比如windows系统把汉字库文件都存储在C:\Windows\Fonts,在该路径下存储了很多的.ttf格式的字库文件,ttf格式是TureTypeFont的缩写,是TrueType类型文件。
同理,ttf类型的字库文件也可以在linux系统上使用,一般linux系统都会把.ttf格式的字库文件存储在 /usr/share/fonts/xxx.ttf
目录检索原理与应用
之前设计的程序只能访问某个路径下的某个文件,如果打算一次访问某个路径下的多个不同类型的文件,就需要用户手动调用open函数实现,但是当文件数量较多时,这种方案并不能满足需求,那请问是否有比较轻松高效的方式来实现访问某个路径下的多个不同类型的文件呢?
回答:当然是有的,在Linux系统下一切皆文件,目录在Linux系统下也属于文件类型之一,可以通过系统IO来进行访问,常见的访问目录的接口有:opendir、readdir、chdir、mkdir、rmdir、remove、getcwd、rewindir等。
⦁ 基本概念
在Linux系统下目录是一种特殊的文件,只不过目录存储的数据的最小单位并不是字符,而是目录项,所以目录与普通文件又有所区别,另外,Linux文件系统下目录和文件夹的含义也并不相同,目录的本质是索引,文件夹的本质是容器。
也就是说,目录是用来保存项目的索引,而不用保存项目本身。Linux 和 UNIX 中的目录并不保存它里面的文件。它们只是记录文件位置的信息。
举个例子:目录和文件夹的区别就相当于门牌号和房子的区别,房子里面可以住人或者存放物品,而门牌号只是记录房子所在的位置,方便用户寻找和访问。
可以看到,在 Linux 或 Unix 操作系统中所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。
Linux系统的文件系统的最顶层是由根目录开始的,使用 / 来表示根目录。在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。如此反复就可以构成一个庞大的文件系统。
⦁ 磁盘结构
思考:如果Linux系统的目录并不存储文件的实际数据内容,而是存储目录项,那请问文件实际的内容存储在哪里?目录的目录项又是什么东西?
回答:文件数据是储存在磁盘上的,磁盘一般就是指计算机的硬盘,硬盘存储数据的最小存储单位叫做扇区。一般计算机每个扇区(Sector)存储512字节,而连续的8个扇区组成了一个数据块(Block),大小为4KB。
计算机一般是以数据块(Block)为单位访问数据,因为这样可以提高CPU的访问效率,而文件数据都存储在数据块中,所以为了能够方便找到数据块中存储数据的位置,就必须找到一个地方存储文件的属性(比如文件的字节数、文件的读写权限、文件的时间戳等),这种存储文件属性信息的区域叫做inode,中文翻译为索引节点,在Linux系统下inode其实是以结构体的形式来存储文件信息的,可以通过man手册的第7章了解inode,如 man 7 inode。
所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区(block),存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。inode区是以数组的形式存储的,数组下标就是inode编号,每个元素就是一个结构体,inode结构体中会有一个指针指向block区,也就是指向存放文件内容的数据块。
思考:既然Linux的文件系统中的每个文件都有一个inode,并且每个inode都有编号,请问应该如何查看文件的inode的编号?
回答:可以直接通过shell命令: ls,有2个选项: -l 显示详细信息 -i 打印文件的索引
⦁ 接口说明
(1) 创建目录
Linux系统提供了一个用于创建目录的mkdir函数接口,第一个参数pathname指的是目录的路径,第二个参数mode用来指定新目录的模式。
(2) 删除目录
Linux系统提供了一个用于删除空目录的rmdir函数接口,第一个参数pathname指的是待删除目录的路径。
(3) 打开目录
Linux系统提供了一个用于打开目录的opendir函数接口,第一个参数pathname指的是待打开目录的路径。
(4) 进入目录
另外,打开目录并不意味着进入目录,而获取目录里面的文件的信息必须要先进入目录,可以用函数 chdir() 进入目录。
(5) 读取目录
Linux系统提供了一个用于读取目录的readdir函数接口,第一个参数dirp指的是待读取目录的目录指针。函数成功返回一个指向该目录中下一个目录项的指针,失败返回NULL。
思考:如果某个目录下存储3个普通文件和1个文件夹,但是程序输出结果并不能区分出来文件的类型,请问应该如何解决该问题?
回答:如果想要区分磁盘中的文件类型,第一个方案是可以利用readdir函数返回的目录项中的成员,另一个方案则是利用stat函数获取文件的信息。
(6) 文件属性
Linux系统提供了一个用于获取文件信息的stat函数接口,第一个参数path指的是待读取文件的路径,第二个参数指的是获取的文件信息结构体的地址。
在结构体 stat 中文件的类型和权限并没有分开存储,而被统一存储到同一个成员 st_mode中。
并发编程的原理与应用
⦁ 线程的概念
思考:一个项目中可能很多的功能模块需要同时运行,并且每个模块中都有独立的循环,但是循环内部没有编写退出条件,就会出现死循环的现象,无法让多个模块同时运行,请问如何解决该问题?
回答:可以在一个进程中创建多条线程来解决,进程指的是进行中的程序,也就是说一个程序得到运行就会变为进程。
windows系统和linux系统都是多任务的操作系统,任务(task)就是系统调度器的调度实体,而任务是存在在进程中的,只不过有些进程中只有一个任务,有些进程中则可能会存在多个任务。
操作系统是以进程为单位分配资源的,如果一个进程中只有一个任务,则该任务拥有进程的全部资源,如果进程中有多个任务,则这些任务共享进程的资源。为了可以让进程中的多个任务得到运行,可以把任务放在线程(thread)中,然后由调度器进行调度,而线程是系统调度资源的最小单位。
线程和进程之间的关系,类似于工厂和工人之间的关系,进程好比是工厂,线程就如同工厂中的工人。一个工厂可以容纳多个工人,工厂负责为所有工人提供必要的资源(电力、产品原料、食堂、厕所等),所有工人共享这些资源,每个工人负责完成一项具体的任务,他们相互配合,共同保证整个工厂的平稳运行。
每个进程执行前,操作系统都会为其分配所需的资源,包括要执行的程序代码、数据、内存空间、文件资源等。一个进程至少包含 1个主线程,可以包含n个子线程,所有线程共享进程的资源,各个线程也可以拥有属于自己的私有资源。
注意:由于系统分配资源是以进程为单位的,而进程至少会执行一个任务,如果进程没有创建其他线程,则程序中的main函数就是一条线程,也被称为主线程。
⦁ 线程的创建
思考:既然进程中可以存在多条线程,每条线程可以执行一个任务,并且线程之间是并发执行的,那请问如何创建线程,以及如何让线程执行某个指定的任务?
回答:用户可以调用线程库中的一个函数实现线程的创建,函数接口叫做:pthread_create()
注意:线程使用的是进程的资源,所以进程退出之后线程也会退出,而进程结束的条件之一就是程序的main函数退出,所以也就是当程序中的main函数退出时,其他的线程也会一起退出。
⦁ 线程的结束
思考:如果用户打算创建一个线程执行一个任务,但是需要线程执行完该任务之后就退出,请问能否实现?如果可以实现,应该如何实现?
回答:Linux系统提供多种方式让线程终止,其中比较常用的方式是调用pthread_exit()函数,利用该接口可以实现让线程终止的目的。
注意:主线程如果调用该函数也可以被终止,但是不会影响进程中其他线程的运行,但是如果主线程中调用exit(),就会导致进程结束,则所有的线程就会终止。