目录
一、基本文件类型
普通文件(-)
(1)文本文件。文件中的内容是由文本构成的,文本指的是ASCII码字符。文件里的内容本质上都是数字(不管什么文件内容本质上都是数字,因为计算机中本身就只有1和0),而文本文件中的数字本身应该被理解为这个数字对应的ASCII码。常见的.c文件,.h文件和.txt文件等都是文本文件。文本文件的好处就是可以被人轻松读懂和编写。所以说文本文件天生就是为人类发明的。
(2)二进制文件。二进制文件中存储的本质上也是数字,只不过这些数字并不是文字的编码数字,而是就是真正的数字。常见的可执行程序文件(gcc编译生成的a. out,arm-linux-gcc编译连接生成的.bin)都是二进制文件。
(3)对比:从本质上来看(就是刨除文件属性和内容的理解)文本文件和二进制文件并没有任何区别。都是一个文件里面存放了数字。区别是理解方式不同,如果把这些数字就当作数字处理则就是二进制文件,如果把这些数字按照某种编码格式去解码成文本字符,则就是文本文件。
(4) 我们如何知道一个文件是 文件文件还是二进制文件?在linux系统层面是不区分这两个的(譬如之前学过的open、read、write等方法操作文件文件和二进制文件时基本没有区别),所以我们无法从文件本身准确知道文件属于哪一种,我们只能本来就知道这个文件的类型然后用这种类型的用法去使用。文本文件的好处就是可以被人轻松读懂和编写。
(5)使用文本文件时,常规用法就是用文本文件编辑器去打开、编辑。常见的文本文件编辑器vim、gedit、 notepad++、 SourceInsight等, 我们用这些文本文件编辑器去打开文件时,编辑器会”read“读出文件二进制数字内容,然后按照编码格式去解码将其还原成文字展现给我们。
如果用文本文件编辑器去打开一个二进制文件会如何?这时候编辑器就以为这个二进制文件还是文本文件然后试图去将其解码成文字,但是解码过程很多数字并不对应有意义的文字所以成了乱码。
(6)反过来用二进制阅读工具去读取文本文件会怎么样?得出的就是文本文字所对应的二进制的编码。arm-linux-gcc编译连接生成的.bin)都是二进制文件。
目录文件 (d)
(1)目录就是文件夹,文件夹在linux中也是一种文件,不过是特殊文件。用vi打开一个文件夹就能看到,文件夹其实也是一种特殊文件,里面存的内容包括这个文件的路径,还有文件夹里面的文件列表。
(2)但是文件夹这种文件比较特殊,本身并不适合用普通的方式来读写。linux中是使用特殊的一些API来专门读写文件夹的。
字符设备文件(c)
- 描述:字符设备文件代表可以一次一个字符进行访问的设备。
- 用途:通常用于串行端口、键盘、鼠标等设备。
- 特性:按字符流进行读写操作,操作系统不进行缓冲。
- 示例:
/dev/ttyS0
(串行端口)、/dev/null
、/dev/random
。
块设备文件(b)
(1)设备文件对应的是硬件设备,也就是说这个文件虽然在文件系统中存在,但是并不是真正存在于硬盘上的一个文件,而是文件系统虚拟制造出来的(叫虚拟文件系统,如/dev /sys /proc等)
(2)虚拟文件系统中的文件大多数不能或者说不用直接读写的,而是用一些特殊的API产生或者使用的。
管道文件 (p)
- 描述:管道文件(FIFO,即先进先出)用于进程间通信(IPC)。
- 用途:允许一个进程将数据写入管道,另一个进程从管道读取数据。
- 特性:先进先出,数据以流的形式通过管道传递。
- 示例:通过
mkfifo
命令创建的FIFO文件。
套接字文件 (s)
- 描述:套接字文件用于网络通信,可以进行进程间通信。
- 用途:用于实现网络通信协议(如TCP/IP)。
- 特性:支持不同类型的网络通信,包括流式套接字(TCP)和数据报套接字(UDP)。
- 示例:本地套接字文件,如
/var/run/docker.sock
。
符号链接文件 (l)
- 描述:符号链接文件是指向另一个文件或目录的引用(快捷方式)。
- 用途:允许多个路径引用同一个文件或目录。
- 特性:链接本身是一个独立的文件,指向的目标可以是文件或目录。
- 示例:通过
ln -s
命令创建的符号链接文件。
二、常用文件属性获取
stat、fstat、lstat函数简介
(1)使用stat查看文件属性
IO Block:文件读写时的的块大小(内容满足该大小才能读写一次硬盘)
Device:文件设备
Inode:静态文件存储在内存的编码(一个文件分配一个inode)
Modify:改变文件内容的时间
Change:文件属性被修改的时间
(2)文件属性信息查看的API有三个: stat、 fstat、 lstat, 三个作用- -样,参数不同,细节略有不同。
(3) linux命令行下还可以去用stat命令去查看文件属性信息,实际上stat命令内部就是使用stat系统调用来实现的。
(4)stat这个API的作用就是让内核将我们要查找属性的文件的属性信息结构体的值放入我们传递给stat函数的buf中,当stat这个API调用从内核返回的时候buf中就被填充了文件的正确的属性信息,然后我们通过查看buf这种结构体变量的元素就可以得知这个文件的各种属性了。
(5) fstat和stat的区别是: stat是从文件名出发得到文件属性信息结构体,而fstat是从一个已经打开的文件fd出发得到一个文件的属性信息。所以用的时候如果文件没有打开(我们并不想打开文件操作而只是希望得到文件属性)那就用stat,如果文件已经被打开了然后要属性那就用fstat效率会更高(stat是从磁盘去读取文件的而fstat是从内存读取动态文件的)。
(6) lstat和stat/fstat的差别在于对于符号链接文件,stat和fstat查阅的是符号链接文件指向的文件的属性,而lstat查阅的是符号链接文件本身的属性。
struct stat结构体简介
(1) struct stat是内核定义的一个结构体,在<sys/stat.h>中声明。这个结构体中的所有元素加起来就是我们的文件属性信息。
struct stat结构体中有如下内容;
用代码判断文件类型
(1)文件类型就是一、d、1.
(2)文件属性中的文件类型标志在structstat结构体的mode_t st_ mode元素中,这个元素其实是一个按位来定义的一个位标志(有点类似于ARMCPU的CPSR寄存器的模式位定义)。这个东西有很多个标志位共同构成,记录了很多信息,如果要查找时按位&操作就知道结果.但是因为这些定义不容易记住,因此linux系统事先定义好了很多宏来进行相应操作。
相关函数有如下这些:
比如S_ISREG宏返回值是1,表示这个文件是一个普通文件,不是普通文件则返回值是0。
我们创建一个普通文件a.txt,并调用stat查看信息,使用S_ISREG函数进行判断。若类型相符,返回1,若不相符,返回0。
示例代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[]){
int re = -1;
struct stat buf;
size_t n = sizeof(buf);
memset(&buf,0,n);
//调用stat获取含文件详细信息的结构体
re = stat("a.txt",&buf);
if (re == -1){
perror("error");
}else{
printf("%d\n",buf.st_mode);
}
//判断是否为普通文件
int result = S_ISREG(buf.st_mode);
if (result == 1){
printf("this is a regular file.\n");
}
运行结果如下:
可以很清晰的得到判断成功,该文件为普通文件
用代码判断文件权限设置
(1)st_ mode中除了记录了文件类型之外,还记录了一个重要信息:文件权限。
(2) linux并没有给文件权限测试提供宏操作,而只是提供了位掩码,所以我们只能
用位掩码来自己判断是否具有相应权限。
我们通常通过获取位掩码后与以下常量进行位运算(即&)来进行权限的判断
常量如下:
位运算原理:
按位与(&)运算符对两个数的每一位执行逻辑与操作:
- 如果两位都是
1
,结果为1
。 - 如果任一位为
0
,结果为0。
假设 buf.st_mode
的二进制表示如下:
buf.st_mode = 1101 1010 1000(假设的二进制值,仅用于解释)
S_IRUSR = 0001 0000 0000
执行按位与运算:
1101 1010 1000
& 0001 0000 0000
----------------------
0001 0000 0000
结果解释:
- 如果
buf.st_mode & S_IRUSR
的结果不为 0,这表示文件所有者的读权限位被设置。 - 如果结果为
0
,则表示文件所有者的读权限位未被设置。
比如位掩码和S_IWUSR进行位运算后,结果不为0,那么我们可以认为该文件所有者有写的权限。
以下为示例代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[]){
int re = -1;
struct stat buf;
size_t n = sizeof(buf);
memset(&buf,0,n);
//调用stat获取含文件详细信息的结构体
re = stat("a.txt",&buf);
if (re == -1){
perror("error");
}else{
printf("%d\n",buf.st_mode);
}
#if 0
//判断是否为普通文件
int result = S_ISREG(buf.st_mode);
if (result == 1){
printf("this is a regular file.\n");
}
#endif
//判断该文件user是否有写的权限
int res = buf.st_mode & S_IRWXU;
if (res){
printf("owner has the right\n",res);
}
}
在unbutu上编译执行:
检验:
可得改文件拥有者具有rwx权限。
由此可知,将位掩码和S_IWUSR进行位运算可以正确判断出相关用户是否具备该写权限。同理,其他常量也可用作权限判断。