一、linux中各种文件类型
(1)普通文件(- regular file)
(1)文本文件。常见的.c文件, .h文件 .txt文件等都是文本文件。文本文件的好处就是可以被人轻松读懂和编写。
(2)二进制文件。常见的可执行程序文件(gcc编译生成的a.out,arm-linux-gcc编译连接生成的.bin)都是二进制文件。
【对比】:
1>.(刨除文件属性和内容的理解),文本文件和二进制文件没有任何区别。
2>.区别:解读方式不同,数字—>二进制文件,文本字符—>文本文件
(2).目录文件(d directory)
Linux中,目录文件就是文件夹(特殊文件),里面包含该文件的路径以及文件夹里面的文件列表。文件夹这种文件比较特殊,Linux中使用特殊的API来专门读写文件夹
(3).字符设备文件(c character)
(4).块设备文件(b block)
(1)设备文件对应的是硬件设备,也就是说这个文件虽然在文件系统中存在,但是并不是真正存在于硬盘上的一个文件,而是文件系统虚拟制造出来的(叫虚拟文件系统,如/dev /sys /proc等)
(2)虚拟文件系统中的文件大多数不能或者说不用直接读写的,而是用一些特殊的API产生或者使用的,具体在驱动阶段会详解。
(5).管道文件(p pipe)
(6).套接字文件(s socket)
(7).符号链接文件(l link)
二、文件属性获取
(1).文件属性:
(1)每个文件中都附带了这个文件的一些属性(属性信息是存在于文件本身中的,但是它不像文件的内容一样可以被vi打开看到,属性信息只能被专用的API打开看到)
(2) struct stat是内核定义的一个结构体,在<sys/stat.h>中声明,所以我们可以用。这个结构体中的所有元素加起来就是我们的文件属性信息
Access:代表最后一次访问(open,write,close……)这个文件的时间,
Modify:指更改文件的内容(write文件)。
Change:指文件属性的更改(增加文件的可执行权限)。
(2).stat、fstat、lstat函数简介
(1)文件属性信息查看的API:stat、fstat、lstat,三个作用一样,参数不同,细节略有不同。
【stat xxx:用于linux命令行下文件属性的查看】
int stat(const char *path, struct stat *buf); //int stat(文件名(全路径),buf)
int fstat(int fd, struct stat *buf); //intfstat(文件描述符,buf)
int lstat(const char *path, struct stat *buf); //int stat(文件名(全路径),buf)
(2).stat:
作用:让内核将我们要查找属性的文件属性信息结构体的值放入我们传递给stat的buf中,通过buf可得知这个文件的各种属性。
(3)fstat和stat的区别是:
stat是从文件名出发得到文件属性信息结构体,而fstat是从一个已经打开的文件fd出发得到一个文件的属性信息。所以用的时候如果文件没有打开(我们并不想打开文件操作而只是希望得到文件属性)那就用stat,如果文件已经被打开了然后要属性那就用fstat效率会更高(stat是从磁盘去读取文件的,而fstat是从内存读取动态文件的)。
(4)lstat和stat/fstat的差别在于:对于符号链接文件,stat和fstat查阅的是符号链接文件指向的文件的属性,而lstat查阅的是符号链接文件本身的属性。
三、文件属性:
/########################################################/
drwxr-xr-x 2 root root 4096 May 18 15:20 3.txt
文件类型 USR GRP OTH USR GRP 块大小 Access 文件名
d rwx r-x r-x 2 root root 4096 May18 15:20 3.txt
/########################################################/
(1) 文件类型就是-、d、l····
三、文件权限
(1).用代码判断文件权限
(1) 文件属性中的文件类型标志在structstat结构体的mode_t 中,st_mode记录了文件的类型和权限。
对于文件类型:Linux系统提供了宏操作【比如:S_ISREG宏返回值是1表示这个文件是一个普通文件,如果文件不是普通文件则返回值是0.】
对于文件权限:Linux系统没有提供宏操作,只提供了位掩码,所以只能通过位掩码来自己判断是否具有相应权限。
(2). ls -l打印出的权限列表
(1)123456789一共9位,3个一组。第一组三个表示文件的属主(owner、user)对该文件的可读、可写、可执行权限;第2组3个位表示文件的属主所在的组(group)对该文件的权限;第3组3个位表示其他用户(others)对该文件的权限。
(2)属主就是这个文件属于谁,一般来说文件创建时属主就是创建这个文件的那个用户。但是我们一个文件创建之后还可以用chown命令去修改一个文件的属主,还可以用chgrp命令去修改一个文件所在的组。
(3). access函数检查权限设置
(1)文本权限管控其实蛮复杂,一般很难很容易的确定对一个文件是否具有某种权限。设计优秀的软件应该是:在操作某个文件之前先判断当前是否有权限做这个操作,如果有再做如果没有则提供错误信息给用户。
(2)access函数可以测试得到当前执行程序的那个用户在当前那个环境下对目标文件是否具有某种操作权限。
(4). chmod/fchmod与权限修改
(1)chmod是一个linux命令,用来修改文件的各种权限属性。chmod命令只有root用户才有权利去执行修改。
(2)chmod命令其实内部是用linux的一个叫chmod的API实现的。
(3)用法:chmod o-r 1.txt //禁止other的可读权限
(5)chown/fchown/lchown与属主修改
(1)linux中有个chown命令来修改文件属主
(2)chown命令是用chown API实现的
(3) chown root 1.txt :将USR属主变为Root
chgrp aston 1.txt :将GRP属主变为Aston
(4) chown: 从文件名出发得到文件属性信息结构体
fchown: 是从一个已经打开的文件fd出发修改文件的属主。
lchown: lchown修改的是符号链接文件的属主。
lchown和chown/fchown的差别在于:对于符号链接文件,chown/fchown修改的是符号链接文件的属主。
(6). umask与文件权限掩码
(1)文件掩码是linux系统中维护的一个全局设置,umask的作用是用来设定我们系统中新创建的文件的默认权限的。
(2)umask命令就是用umask API实现的
(3) umask 0000 -rw-rw-rw- 1 root root 0 May 18 18:22 1.txt //可读写
umask 0022 -rw-r--r-- 1 root root 0 May 18 18:18 2.txt //可读
umask 0044 -rw--w--w- 1 root root 0 May 18 18:18 3.txt //可写
umask 0066 -rw------- 1 root root 0 May 18 18:19 4.txt //不可读写
四、读取目录文件
(1)、opendir与readdir函数
(1)opendir打开一个目录后得到一个DIR类型的指针给readdir使用
【DIR*opendir(const char *name);】
(2)readdir函数调用一次就会返回一个struct 【struct dirent*readdir(DIR *dirp);】
dirent类型的指针,这个指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。
(3)readdir调用一次只能读出一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。readdir函数内部户记住哪个目录项已经被读过了哪个还没读,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
(4)、dirent结构体
structdirent
{
long d_ino; /* inode number索引节点号 */
off_t d_off; /* offset tothis dirent 在目录文件中的偏移 */
unsigned short d_reclen;/* length of this d_name 文件名长 */
unsigned char d_type; /*the type of d_name 文件类型 */
char d_name [NAME_MAX+1];/* file name (null-terminated) 文件名,最长255字符 */
}
(2)可重入函数介绍
(1)readdir函数和我们前面接触的一些函数是不同的,首先readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir其实readir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法是readdir不可重入的关键。
(2)readdir在多次调用时是有关联的,这个关联也标明readdir函数是不可重入的。
(3)库函数中有一些函数当年刚开始提供时都是不可重入的,后来意识到这种方式不安全,所以重新封装了C库,提供了对应的可重复版本(一般是不可重入版本函数名_r)
应用编程细节问题分析:
(1)perror(系统函数,返回值为字符串,适合人看)——>errno(系统错误编号,返回值为数字,不适合人看)
(2)man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查库函数
(3)exit、_exit、_Exit退出进程
(1)当我们程序在前面步骤操作失败导致后面的操作都没有可能进行下去时,应该在前面的错误监测中结束整个程序,不应该继续让程序运行下去了。
(2)我们如何退出程序?
第一种;在main用return,一般原则是程序正常终止return0,如果程序异常终止则return -1。
第一种:正式终止进程(程序)应该使用exit或者_exit或者_Exit之一。
B>.int open(const char * pathname, int flags, mode_t mode);
open函数在使用O_CREAT标志去创建文件时,可以使用第三个参数mode来指定要创建的文件的权限。mode使用4个数字来指定权限的,其中后面三个很重要,对应我们要创建的这个文件的权限标志。譬如一般创建一个可读可写不可执行的文件就用0666
C>.read和write的count
(1)count和返回值的关系。count参数表示我们想要写或者读的字节数,返回值表示实际完成的要写或者读的字节数。实现的有可能等于想要读写的,也有可能小于(说明没完成任务)
(2)count再和阻塞非阻塞结合起来,就会更加复杂。如果一个函数是阻塞式的,则我们要读取30个,结果暂时只有20个时就会被阻塞住,等待剩余的10个可以读。
(3)有时候我们写正式程序时,我们要读取或者写入的是一个很庞大的文件(譬如文件有2MB),我们不可能把count设置为2*1024*1024,而应该去把count设置为一个合适的数字(譬如2048、4096),然后通过多次读取来实现全部读完。