文章目录

  • 文件类型
  • 普通文件(regular file:-)
  • 目录文件(directory file:d)
  • 字符特殊文件( character special file: c)
  • 块设备文件(block special file: b):对应块设备(如磁盘等)。
  • FIFO(fifo:p)
  • 套接字文件( socket: s)
  • 符号连接(symbolic link: l):
  • 获取文件属性
  • stat函数
  • st_mode
  • st_size
  • 空洞文件的意义
  • 制作空洞文件
  • 文件权限掩码
  • 如何修改文件权限掩码


文件类型

在Linux下一切皆是文件,从应用层(应用程序层)看待底层机制时,皆以文件的方式来看待这些机制.但是不同的底层机制,毕竟是不同的,比如底层驱动程序,就分为字符设备驱动和块设备驱动,根据底层机制的不同,文件被分为了7种类型,分布是 - d c s p c b

普通文件(regular file:-)

普通文件根据存放的内容的不同,又分为如下两种

  • 文本文件
    存放的都是文字编码,文本编辑器打开后,会将这些文字编码翻译为文字图形,以供人识别。
  • 纯二进制文件(机器码)
    比如经过编译后得到的可执行文件,里面放的是cpu执行的纯二进制机器码,由于文编编辑器只认识文字编码,所以用文本编辑器打开后,显示的内容无法是错乱的,无法辨识。

其实不管存放的是文字编码,还是机器码,在计算机中存储时,其实都是以二进制形式存放的,只不过我们这里可刻意的把机器码这类非文字编码的数据,特意强调为了二进制数据。

目录文件(directory file:d)

目录是一种特殊的文件,专门用于管理其他文件。

字符特殊文件( character special file: c)

字符设备文件,就是字符设备驱动程序,在上层的表现形式。

当应用程序调用底层字符设备驱动程序,实现对某个字符设备进行读写时,上层就需要对接底层的字符驱动程序,字符设备驱动在上层,会以"字符设备文件"的形式表现出来,我们通过open、read、write去读写字符设备文件,就实现了和底层字符设备驱动程序的交互。

块设备文件(block special file: b):对应块设备(如磁盘等)。

块设备文件,是块设备驱动程序在上层的表现形式。

字符设备与块设备有什么区别?

  • 字符设备
    以字节为单位来操作数据。
    比如:键盘、鼠标、显示器都等是字符设备。
    字符设备的驱动程序,就称为"字符设备驱动程序”。
  • 块设备
    块设备存储的数据量往往非常答,为了提高读写效率,都是以块(1024字节)为单位来操作数据。
    比如:电脑硬盘、移动硬盘、u盘等,凡是涉及大量数据存储的,都是以块为单位来操作数据的,都是块设备。块设备的驱动程序,就成为"块设备驱动程序”。

FIFO(fifo:p)

管道文件,用于实现不同进程(程序)之间的通信,管道是os提供的一种纯代码层面的通信机制。
sudoers文件属性为777 文件属性hs_运维

套接字文件( socket: s)

专门用于网络通信的文件。
讲到网络编程时,再来具体介绍。

符号连接(symbolic link: l):

其实就是一种快捷图标,背后指向了另外一个文件。

file 文件

查看文件属性

  • 如果查看的是文本文件
    会提醒你,它是文字编码格式的文件。
  • 如果你查看的是纯二进制文件((机器码)
    会提示你,这是一个可以运行的可执行文件。
    a.out: ELF 64-bit LSB executable, x86-64,dynamically linked,/lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,not strippe
  • ELF: Linux下可执行文件的格式,windows下的可执行文件是PE格式对
    应格式的可执行文件,只能在对应的os下运行。
  • 64-bit:文件里面的机器码是64位.的
  • LSB:小端序
  • executable:明确告诉你,该文件是一个可执行文件·x86-64:运行的是x86架构64位的cpu
  • dynamically linked,/ lib64/ ld-linux-x86-64.so.2
    程序使用的库是动态链接库,库名叫/lib64/ld-linux-x86-64.so.2
  • for GxU/Linux 2.6.32:运行的系统是Linux系统〈ubuntu) , Linux 2.6.32是ubuntu所用Linux内核的版本号
  • not strippe:程序没有被瘦身,里面包含有各种用于调试用的信息,当这个程序最终发布时,会使用strip命令为程序瘦身,去除里面的无用信息,让程序变的更小。

获取文件属性

stat、lstat、fstat函数

ls命令其实就是调用了这三个函数中的lstat来实现的,我们可以调用lstat函数来自己实现一个ls命令。

stat函数

#include <sys/types.h>                                                               
#include <sys/stat.h>                                                               
#include <unistd.h>    
int stat(const char *path, struct stat *statbuf); 
int lstat(const char *path, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);

statlstat唯一的区别就是stat获取链接文件属性时会直接获取链接指向的文件的属性,而lstat会返回链接文件的属性,而fstatstat唯一区别是fstat使用文件描述符而非文件路径。

  1. 功能:获取文件的属性信息。
    每个文件的属性信息,都是存在块设备上,该文件自己的inode节点(索引节点)空间中。
    调用stat函数时,文件系统通过stat给的path,到块设备上索引到该文件的inode节点空间,然后将里面的文件属性信息,读到应用程序的缓存中,如此就得到了文件的属性信息。
    文件属性数据中转的过程:
    应用缓存<–stat函数提供的内核缓存<–驱动程序的缓存<–块设备上的inode结点
  2. 返回值
    调用成功,返回0,失败返回-1,errno被设置。
  3. 参数
  • path:文件路径名
  • statbuf:应用缓存,用于存放读到的文件属性信息
struct stat{
	dev_t st_dev;/*块设备号(ID)*/
	ino_t st_ino;/*inode结点号,文件属性信息所存inode节点的编号*/
	mode_t l st_mode;/*文件类型和文件权限 ls*/
	nlink_t st_nlink;/*链接数 ls*/
	uid_t st_uid;/*文件所属用户ID ls*/
	gid_t st_gid;/*文件所属组ID ls*/
	dev_t st_rdev;/*字符设备ID*/
	off_t st_size;/*文件大小*/
	blksize_t st_blksize;/*系统每次按块IO操作时,块的大小(一般是512或1024)*/
    blkcnt_t st_blocks;/*块的索引号*/
/*windows下,文件的时间,同样也分为这三种*/
    time_t st_atime;/*最后一次访问时间,read ls*/
    time_t st_mtime;/*最后一次修改时间,write*/
	time_t st_ctime;/*最后一次属性修改的时间,如权限被修改,文件所有者(属主)被修改*/
};
//其中有ls标记的是ls会显示的内容

st_mode

st_mode 本质就是一个16位二进制数
文件类型 设置位 文件权限
**** **** *** *** ***

  • 文件类型(定义在<sys/stat.h>)

二进制

含义

(1000 000000000000)

代表普通文件

(0100 000000000000)

代表目录文件

(0110 000000000000)

代表块设备文件

(0011 000000000000)

代表字符设备文件

(0001 000000000000)

代表管道文件

(1100 000000000000)

代表套接字文件

(1010 000000000000)

代表符号链接文件

  • 文件权限
    user group other
    r w x r w x r w x
    0 1 - 0 1 - 0 1 -

st_size

文件长度,只对普通文件、目录及符号链接有意义因为只有普通文件、目录、以及符号链接文件才有实际的数据,有数据才有文件长度。其它的文件在块设备上只存储了文件属性,它们只是挂了一个文件名,以文件的形式进行管理而已,没有实际的数据,所以对于这些文件来说,文件大小是没有意义的。

符号链接文件就是一个快捷键,背后指向了某个文件。
符号链接文件的数据,就是所指向文件的文件名,所以它的文件大小指的就是这个文件名的字符个数。

#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path,off_t length);
int ftruncate(int fd, off_t length) ;

函数功能:将文件长度截短为length所指定长度。
truncate利用文件路径名操作,ftruncate利用文件描述符操作。

length的大小可以大于文件实际大小,文件截断长度>文件长度时,多余的部分填放空洞。

ls查看到的只是文件的理论大小,但是空洞部分并不占用实际物理存储空间。du命令:查看文件在块设备上,实际占用的物理空间。

在一般文件的情况下,对于普通文件来说,文件数据的理论大小=在块设备上实际占用的空间大小。
但是空洞文件却不是这样的,对于空洞文件来说,文件数据的理论大小〉在块设备上实际占用的空间大小。

空洞文件的意义

打个比方,我承诺给你一亩地,但是你又不是马上就要用满这一亩地,是一点一点来占用的,如果我现在一下子就把一亩地全部给你,但是你要花费很久时间才会把地全用上,在你占满之前,一直有相当部分的空间被闲置不用,显然非常浪费空间资源。
解决办法是,我先承诺说给你一亩地,但是这一亩地先不全部给你,你搬一部分东西过来时,我给你一部分空间,按照这样的方式,直到把1亩地的空间全部给你,在你没有用满一亩地之前,其它的空间我就可以用作它用。

制作空洞文件
  • truncate、ftrucate制作
    文件截短长度>文件长度时,多余的部分就是空洞。
  • 使用lseek制作
    将文件读写位置调整到文件尾部之后,然后写点数据,中间空出的部分就是空洞。

文件权限掩码

111 111 111 (0777) 指定权限
&
~000 000 010 (0002)文件权限掩码

111 111 101 (0775) 实际文件权限

文件权限掩码是用来限制其他用户的权限,防止其他用户修改你的文件

每一个进程都有一个文件权限掩码,进程修改只是当前进程的文件权限掩码,对其它进程的文件权限掩码无影响。

如何修改文件权限掩码

#include <sys/types.h>                                                               
#include <sys/stat.h>                                                               
mode_t umask(mode_t mask);
  1. 功能:修改文件权限掩码
  2. 参数
    mask:新的文件权限掩码
  3. 返回值
    umask不会调用失败。返回值是旧的文件权限掩码。