文件属性信息 3个月前

编程语言
395
文件属性信息

众所周知,Linux是一个基于文件的操作系统,因此作为文件本身也就有很多属性,如果想要查看某一个文件的属性有两种方式:命令函数。 虽然有两种方式但是它们对应的名字是相同的,叫做stat。另外使用file命令也可以查看文件的一些属性信息。

1. file 命令

该命令用来识别文件类型,也可用来辨别一些文件的编码格式。它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的。

命令语法如下:

# 参数在命令中的位置没有限制
$ file 文件名 [参数]

file 命令的参数是可选项, 可以不加, 常用的参数如下表:

参数 功能
-b 只显示文件类型和文件编码, 不显示文件名
-i 显示文件的 MIME 类型
-F 设置输出字符串的分隔符
-L 查看软连接文件自身文件属性

1.1 查看文件类型和编码格式

使用不带任何选项的 file 命令,即可查看指定文件的类型和文件编码信息。

# 空文件
$ file 11.txt 
11.txt: empty

# 源文件, 编码格式为: ASCII
$ file b.cpp
b.cpp: C source, ASCII text

# 源文件, 编码格式为: UTF-8 
robin@OS:~$ file test.cpp 
test.cpp: C source, UTF-8 Unicode (with BOM) text, with CRLF line terminators

# 可执行程序, Linux中的可执行程序为 ELF 格式
robin@OS:~$ file a.out 
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=5317ae9fba592bf583c4f680d8cc48a8b58c96a5, not stripped

1.2 只显示文件格式以及编码

使用-b参数,可以使 file 命令的输出不出现文件名,只显示文件格式以及编码。

# 空文件
$ file 11.txt -b
empty

# 源文件, 编码格式为: ASCII
$ file b.cpp -b
C source, ASCII text

# 源文件, 编码格式为: UTF-8 
robin@OS:~$ file test.cpp  -b
C source, UTF-8 Unicode (with BOM) text, with CRLF line terminators

# 可执行程序, Linux中的可执行程序为 ELF 格式
robin@OS:~$ file a.out  -b
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=5317ae9fba592bf583c4f680d8cc48a8b58c96a5, not stripped

1.3 显示文件的 MIME 类型

给file命令添加-i参数,可以输出文件对应的 MIME 类型的字符串。

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。 是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。 多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

# charset 为该文件的字符编码

# 源文件, MIME类型: text/x-c, 字符编码: utf-8
$ file occi.cpp -i
occi.cpp: text/x-c; charset=utf-8

# 压缩文件, MIME类型: application/gzip, 字符编码: binary
$ file fcgi.tar.gz -i
fcgi.tar.gz: application/gzip; charset=binary

# 文本文件, MIME类型: text/plain, 字符编码: utf-8
$ file english.txt -i
english.txt: text/plain; charset=utf-8

# html文件, MIME类型: text/html, 字符编码: us-ascii
$ file demo.html -i
demo.html: text/html; charset=us-ascii

1.4 设置输出分隔符

在 file 命令中,文件名和后边的属性信息默认使用冒号(:)分隔,我们可以通过 -F 参数修改分隔符 分隔符可以是单字符也可以是一个字符串,如果分隔符是字符串需要将这个参数值写到引号中(单/双引号都可以)。

# 默认格式输出
$ file english.txt 
english.txt: UTF-8 Unicode text, with very long lines, with CRLF line terminators

# 修改分隔符为字符串 “==>"
$ file english.txt -F "==>"
english.txt==> UTF-8 Unicode text, with very long lines, with CRLF line terminators

$ file english.txt -F '==>'
english.txt==> UTF-8 Unicode text, with very long lines, with CRLF line terminators

# 修改分隔符为单字符 '='
$ file english.txt -F = 
english.txt= UTF-8 Unicode text, with very long lines, with CRLF line terminators

1.5 查看软连接文件

软连接文件是一个特殊格式的文件, 查看这种格式的文件可以得到两种结果: 第一种是软连接文件本身的属性信息,另一种是链接文件指向的那个文件的属性信息。 直接通过 file 查看文件属性得到的是链接文件指向的文件的信息 如果添加参数 -L得到的链接文件自身的属性信息。

# 使用 ls 查看链接文件属性信息
$ ll link.lnk 
lrwxrwxrwx 1 root root 24 Jan 25 17:27 link.lnk -> /root/luffy/onepiece.txt

# 使用file直接查看链接文件信息: 得到的是链接文件指向的那个文件的名字
$ file link.lnk 
link.lnk: symbolic link to `/root/luffy/onepiece.txt'

# 使用 file 查看链接文件自身属性信息, 添加参数 -L
$ file link.lnk -L
link.lnk: UTF-8 Unicode text

2. stat 命令

stat命令显示文件或目录的详细属性信息包括文件系统状态,比ls命令输出的信息更详细。

# 语法格式
# 参数在命令中的位置没有限制
$ stat [参数] 文件或者目录名

关于这个命令的可选参数如下表:

参数 功能
-f 不显示文件本身的信息,显示文件所在文件系统的信息
-L 查看软链接文件关联的文件的属性信息
-c 查看文件某个单个的属性信息
-t 简洁模式,只显示摘要信息,不显示属性描述

2.1 显示所有属性

$ stat english.txt 
  File: 'english.txt'
  Size: 129567          Blocks: 256        IO Block: 4096   regular file
Device: 801h/2049d      Inode: 526273      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1001/   robin)   Gid: ( 1001/   robin)
Access: 2021-01-31 00:00:36.791490304 +0800
Modify: 2021-01-31 00:00:36.791490304 +0800
Change: 2021-01-31 00:00:36.791490304 +0800
 Birth: -

在输出的信息中我们可以看到很多属性,

  • File: 文件名
  • Size: 文件大小, 单位是字节
  • Blocks: 文件使用的数据块总数
  • IO Block:IO块大小
  • regular file:文件的实际类型,文件类型不同,该关键字也会变化
  • Device:设备编号
  • Inode:Inode号,操作系统用inode编号来识别不同的文件,找到文件数据所在的block,读出数据。
  • Links:硬链接计数
  • Access:文件所有者+所属组用户+其他人对文件的访问权限
  • Uid: 文件所有者名字和所有者ID
  • Gid:文件所有数组名字已经组ID
  • Access Time:表示文件的访问时间。当文件内容被访问时,这个时间被更新
  • Modify Time:表示文件内容的修改时间,当文件的数据内容被修改时,这个时间被更新
  • Change Time:表示文件的状态时间,当文件的状态被修改时,这个时间被更新,例如:文件的硬链接链接数,大小,权限,Blocks数等。
  • Birth: 文件生成的日期

2.2 只显示系统信息

给 stat 命令添加 -f参数将只显示文件在文件系统中的相关属性信息, 文件自身属性不显示

$ stat luffy/ -f
  File: "luffy/"
    ID: 47d795d8889d00d3 Namelen: 255     Type: ext2/ext3
Block size: 4096       Fundamental block size: 4096
Blocks: Total: 10288179   Free: 8991208    Available: 8546752
Inodes: Total: 2621440    Free: 2515927

2.3 软连接文件

使用 stat 查看软链接类型的文件, 默认显示的是这个软链接文件的属性信息, 添加参数 -L 就可以查看这个软连接文件关联的文件的属性信息了。

# 查看软件文件属性 -> 使用 ls -l
ls -l link.lnk 
lrwxrwxrwx 1 root root 24 Jan 25 17:27 link.lnk -> /root/luffy/onepiece.txt

# 使用 stat 查看软连接文件属性信息
$ stat link.lnk 
  File: ‘link.lnk’ -> ‘/root/luffy/onepiece.txt’
  Size: 24              Blocks: 0          IO Block: 4096   symbolic link
Device: fd01h/64769d    Inode: 393832      Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-01-30 23:46:29.922760178 +0800
Modify: 2021-01-25 17:27:12.057386837 +0800
Change: 2021-01-25 17:27:12.057386837 +0800
 Birth: -

# 使用 stat 查看软连接文件关联的文件的属性信息
$ stat link.lnk -L
  File: ‘link.lnk’
  Size: 3700              Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 660353      Links: 2
Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-01-30 23:46:53.696723182 +0800
Modify: 2021-01-25 17:54:47.000000000 +0800
Change: 2021-01-26 11:57:00.587658977 +0800
 Birth: -

2.4 简洁输出

使用 stat 进行简洁信息输出的可读性不是太好, 所有的属性描述都别忽略了, 如果只想得到属性值, 可以给该命令添加-t参数:

$ stat luffy/ -t
luffy/ 4096 8 41fd 1001 1001 801 662325 8 0 0 1611659086 1580893020 1580893020 0 4096

2.5 单个属性输出

如果每次只想通过 stat 命令得到某一个文件属性, 可以给名添加 -c 参数。 不同的文件属性分别对应一些定义好的特殊符号,想得到哪个属性值,将其指定到参数 -c 后边即可。

属性对应的字符如下表:

格式化字符 功能
%a 文件的八进制访问权限(#和0是输出标准)
%A 人类可读形式的文件访问权限(rwx)
%b 已分配的块数量
%B 报告的每个块的大小(以字节为单位)
%C SELinux 安全上下文字符串
%d 设备编号 (十进制)
%D 设备编号 (十六进制)
%F 文件类型
%g 文件所属组组ID
%G 文件所属组名字
%h 用连接计数
%i inode编号
%m 挂载点
%n 文件名
%N 用引号括起来的文件名,并且会显示软连接文件引用的文件路径
%o 最佳I/O传输大小提示
%s 文件总大小, 单位为字节
%t 十六进制的主要设备类型,用于字符/块设备特殊文件
%T 十六进制的次要设备类型,用于字符/块设备特殊文件
%u 文件所有者ID
%U 文件所有者名字
%w 文件生成的日期 ,人类可识别的时间字符串 – 获取不到信息不显示
%W 文件生成的日期 ,自纪元以来的秒数 (参考 %X )– 获取不到信息不显示
%x 最后访问文件的时间, 人类可识别的时间字符串
%X 最后访问文件的时间, 自纪元以来的秒数(从1970.1.1开始到最后一次文件访问的总秒数)
%y 最后修改文件内容的时间, 人类可识别的时间字符串
%Y 最后修改文件内容的时间, 自纪元以来的秒数(参考 %X )
%z 最后修改文件状态的时间, 人类可识别的时间字符串
%Z 最后修改文件状态的时间, 自纪元以来的秒数(参考 %X )

仔细阅读上表可以知道:文件的每一个属性都有一个或者多个与之对应的格式化字符,这样就可以精确定位所需要的属性信息了,举几个例子作为参考:

$ stat occi.cpp -c %a
644

$ stat occi.cpp -c %A           
-rw-r--r--

# 使用 ls -l 验证权限
$ ll occi.cpp 
-rw-r--r-- 1 robin robin 1406 Jan 31 00:00 occi.cpp        # 0664

$ stat link.lnk -c %N
'link.lnk' -> '/home/robin/english.txt'

$ stat link.lnk -c %y
2021-01-31 10:48:52.317846411 +0800

3. stat/lstat 函数

stat/lstat 函数的功能和 stat 命令的功能是一样的, 只不过是应用场景不同。 这两个函数的区别在于处理软链接文件的方式上

  • lstat(): 得到的是软连接文件本身的属性信息
  • stat(): 得到的是软链接文件关联的文件的属性信息
//函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
  • 参数:
    • pathname: 文件名, 要获取这个文件的属性信息
    • buf: 传出参数, 文件的信息被写入到了这块内存中
  • 返回值: 函数调用成功返回 0,调用失败返回 -1

这个函数的第二个参数是一个结构体类型, 这个结构体相对复杂, 通过这个结构体可以存储得到的文件的所有属性信息, 结构体原型如下:

struct stat {
    dev_t          st_dev;            // 文件的设备编号
    ino_t           st_ino;            // inode节点
    mode_t      st_mode;              // 文件的类型和存取的权限, 16位整形数  -> 常用
    nlink_t        st_nlink;         // 连到该文件的硬连接数目,刚建立的文件值为1
    uid_t           st_uid;           // 用户ID
    gid_t           st_gid;           // 组ID
    dev_t          st_rdev;          // (设备类型)若此文件为设备文件,则为其设备编号
    off_t            st_size;          // 文件字节数(文件大小)   --> 常用
    blksize_t     st_blksize;       // 块大小(文件系统的I/O 缓冲区大小)
    blkcnt_t      st_blocks;        // block的块数
    time_t         st_atime;         // 最后一次访问时间
    time_t         st_mtime;         // 最后一次修改时间(文件内容)
    time_t         st_ctime;         // 最后一次改变时间(指属性)
};

3.1 获取文件大小

下面调用 stat() 函数, 以代码的方式演示一下如何得到某个文件的大小:

#include <sys/stat.h>

int main()
{
    // 1. 定义结构体, 存储文件信息
    struct stat myst;
    // 2. 获取文件属性 english.txt
    int ret = stat("./english.txt", &myst);
    if(ret == -1)
    {
        perror("stat");
        return -1;
    }

    printf("文件大小: %d\n", (int)myst.st_size);

    return 0;
}

3.2 获取文件类型

文件的类型信息存储在 struct stat 结构体的st_mode成员中, 它是一个 mode_t 类型, 本质上是一个16位的整数。 Linux API中为我们提供了相关的宏函数,通过对应的宏函数可以直接判断出文件是不是某种类型,这些信息都可以通过 man 文档(man 2 stat)查询到。

相关的宏函数原型如下:

// 类型是存储在结构体的这个成员中: mode_t  st_mode;  
// 这些宏函数中的  m 对应的就是结构体成员  st_mode
// 宏函数返回值: 是对应的类型返回-> 1, 不是对应类型返回0

S_ISREG(m)  is it a regular file?  
    - 普通文件
S_ISDIR(m)  directory?
    - 目录
S_ISCHR(m)  character device?
    - 字符设备
S_ISBLK(m)  block device?
    - 块设备
S_ISFIFO(m) FIFO (named pipe)?
    - 管道
S_ISLNK(m)  symbolic link?  (Not in POSIX.1-1996.)
    - 软连接
S_ISSOCK(m) socket?  (Not in POSIX.1-1996.)
    - 本地套接字文件

在程序中通过宏函数判断文件类型, 实例代码如下:

int main()
{
    // 1. 定义结构体, 存储文件信息
    struct stat myst;
    // 2. 获取文件属性 english.txt
    int ret = stat("./hello", &myst);
    if(ret == -1)
    {
        perror("stat");
        return -1;
    }

    // 判断文件类型
    if(S_ISREG(myst.st_mode))
    {
        printf("这个文件是一个普通文件...\n");
    }

    if(S_ISDIR(myst.st_mode))
    {
        printf("这个文件是一个目录...\n");
    }
    if(S_ISLNK(myst.st_mode))
    {
        printf("这个文件是一个软连接文件...\n");
    }

    return 0;
}

3.2 获取文件权限

用户对文件的操作权限也存储在 struct stat 结构体的st_mode成员中, 在这个16位的整数中不同用户的权限存储位置如下图 如果想知道有没有相关权限可以通过按位与(&)操作将这个标志位值取出判断即可。

在这里插入图片描述

Linux 中为我们提供了用于不同用户不同权限判定使用的宏,具体信息如下:

关于变量 st_mode: 
- st_mode -- 16位整数
    ○ 0-2 bit -- 其他人权限
        - S_IROTH    00004  读权限   100
        - S_IWOTH    00002  写权限   010
        - S_IXOTH    00001  执行权限  001
        - S_IRWXO    00007  掩码, 过滤 st_mode中除其他人权限以外的信息
    ○ 3-5 bit -- 所属组权限
        - S_IRGRP    00040  读权限
        - S_IWGRP    00020  写权限
        - S_IXGRP    00010  执行权限
        - S_IRWXG    00070  掩码, 过滤 st_mode中除所属组权限以外的信息
    ○ 6-8 bit -- 文件所有者权限
        - S_IRUSR    00400    读权限
        - S_IWUSR    00200    写权限
        - S_IXUSR    00100    执行权限
        - S_IRWXU    00700    掩码, 过滤 st_mode中除文件所有者权限以外的信息
    ○ 12-15 bit -- 文件类型
        - S_IFSOCK   0140000 套接字
        - S_IFLNK    0120000 符号链接(软链接)
        - S_IFREG    0100000 普通文件
        - S_IFBLK    0060000 块设备
        - S_IFDIR    0040000 目录
        - S_IFCHR    0020000 字符设备
        - S_IFIFO    0010000 管道
        - S_IFMT     0170000 掩码,过滤 st_mode中除文件类型以外的信息
            
############### 按位与操作举例 ###############            
    1111 1111 1111 1011   # st_mode
    0000 0000 0000 0100   # S_IROTH
&
----------------------------------------
    0000 0000 0000 0000   # 没有任何权限

通过仔细阅读上边提供的宏信息, 我们可以知道处理使用它们得到用户对文件的操作权限, 还可以用于判断文件的类型(判断文件类型的第二种方式),具体操作方式可以参考如下代码:

#include <sys/stat.h>

int main()
{
    // 1. 定义结构体, 存储文件信息
    struct stat myst;
    // 2. 获取文件属性 english.txt
    int ret = stat("./hello", &myst);
    if(ret == -1)
    {
        perror("stat");
        return -1;
    }

    printf("文件大小: %d\n", (int)myst.st_size);

    // 判断文件类型
    if(S_ISREG(myst.st_mode))
    {
        printf("这个文件是一个普通文件...\n");
    }

    if(S_ISDIR(myst.st_mode))
    {
        printf("这个文件是一个目录...\n");
    }
    if(S_ISLNK(myst.st_mode))
    {
        printf("这个文件是一个软连接文件...\n");
    }

    // 文件所有者对文件的操作权限
    printf("文件所有者对文件的操作权限: ");
    if(myst.st_mode & S_IRUSR)
    {
        printf("r");
    }
    if(myst.st_mode & S_IWUSR)
    {
        printf("w");
    }
    if(myst.st_mode & S_IXUSR)
    {
        printf("x");
    }
    printf("\n");
    return 0;
}
image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2222728
累计阅读

热门教程文档

Rust
84小节
MySQL
34小节
Redis
14小节
MyBatis
19小节
Next
43小节