1. Linux中各种文件类型
1·1 普通文件(文件标识: - )
(1)文本文件:文件中都是由文本构成的,文本指的是ASCII码字符。文件里面的内容本质上都是数字(不管什么文件内容本质上都是数字,因为计算机中本身就只识别 0 和 1),而文本文件中的数字本身应该被理解为这个数字对应的ASCII码。文本文件服务于人。常见的 .c 文件, .h文件 ,.txt文件都是文本文件,文本文件方便读懂和编写。
常见文本编辑器:vim , gedit ,notepad++ , sourcetnsight 等等。
(2)二进制文件
二进制文件存储的就是数字,真正的数字。
如果用文本编辑器去打开一个二进制文件会如何?出现乱码。
反过来,二进制阅读工具读取文本文件会如何?得出的就是文本文件所对应的二进制的编码。
1·2 目录文件 (文件标识 : d directory)
(1)目录文件就文件夹,文件夹在Linux系统中也是一种文件,是一种特殊文件。用vi打开一个文件夹就能看见这个文件夹的路径和文件夹里面的文件列表。
(2)文件夹这种文件比较特殊,本身不适合用普通的方式来读写。Linux系统中使用特殊的API来专门读写文件夹的。
1·3 字符设备文件(c character )
1·4 块设备文件(b block )
(1)设备文件对应的是硬盘设备,也就是说这个文件虽然在文件系统中存在,但是并不是这种存在于硬盘上的一个文件,而是文件系统虚拟指针出来的,(叫虚拟文件系统,比如 / dev / sys / proc 等)
(2)虚拟文件系统中的文件大多数不能或者说不用直接读写,而是用一些特殊API产生或者使用,具体在驱动阶段会详解。
1·5 管道文件(p pipe)
1·6 套接字文件(s socket)
1·7 符号链接文件(l link)
2. 常用文件属性获取
2·1 stat ,fstat ,lstat 函数介绍
Linux中由一条指令: stat xxx 可用查询xxx文件的属性。
stat 指令就是用stat函数封装来的
文件属性查看API有三个:stat ,fstat ,lstat 。三个作用一样,参数不同,细节略有不同,具体man手册。
**int stat(const char pathname, struct stat statbuf);
const char *pathname : 输入型参数
struct stat *statbuf : 输出型参数,(因为不是const修饰)将文件的属性放在statbuf指向的结构体变量里面。(struct stat 是结构体类型,struct stat *statbuf是结构体指针,指向的是另外一个结构体的地址,用来存放我们需要查询的文件的属性信息,到时候只要访问结构体就欧克)
*int fstat(int fd, struct stat statbuf);
stat 与 fstat 的区别是:
stat是从文件名(或者是文件路径)得到文件属性结构体,而fstat是从一个已经打开的文件fd来得到一个文件属性。所以用的时候如果文件没有打开(我们并不想打开一个文件而只是希望得到文件的属性,就用stat;如果我们已经打开了一个文件,然后希望得到文件属性那就用fstat效率会更高。)
**int lstat(const char pathname, struct stat statbuf);
lstat 和 stat / fstat 的差别在于:对于符号链接文件,stat 和 fstat 查阅的是符号链接文件指向的文件的属性,而lstat查阅的是符号链接文件本身的属性。
2·2 struct stat 结构体介绍
(1)struct stat是内核定义的一个结构体。这个结构体中的所有元素加起来就是我们的文件属性。
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
2·3 用代码得到文件属性
(1)文件属性就是 - , d, l …
(2)文件属性中的文件类型标志在struct stat 结构体的mode_t st_mode 元素中,这个元素其实是一个按位来定义的一个标志位(有点类似于ARM CPU的CPSR寄存器的模式位定义)。这个元素有很多个标志位共同构成,记录了很多信息,查找时按位&操作就知道结果了,但是因为这些位定义不易记住,因此Linux系统里面先定义好了很多宏来进行相应的操作。
(3)
S_ISREG(m) is it a regular file? 这个宏返回值是1就表示这个文件是一个普通文件,返回0 就表示不是普通文件
S_ISDIR(m) directory? 是否为目录?1----是
S_ISCHR(m) character device?是否为字符设备文件? 1---是
S_ISBLK(m) block device?是否为块设备文件?1---是
S_ISFIFO(m) FIFO (named pipe)?是否为fifo文件?1---是
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)是否为符号链接?
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)是否为套接字文件?
2·4 用代码判断文件权限设置
(1)st_mode 中出来记录文件类型之外,还记录了一个重要信息:文件权限。
(2)Linux没有给文件权限测试提供宏操作,而只是提供了位掩码,我们只能用位掩码来判断文件权限。
The following mask values are defined for the file mode component of
the st_mode field:
S_ISUID 04000 set-user-ID bit
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
宿主是否有读权限?位与后结果需要右移8位
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and
execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
使用例子:
stat(pathname, &sb);
if ((sb.st_mode & S_IRWXG) == S_IRWXG) {
/* Handle regular file */
}
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define FILENAME "newfile"
int main (void)
{
int fd = -1,ret = -1;
struct stat buf ;
memset(&buf,0,sizeof(buf)); // memset 后buf里面全是0,空白的
fd = open(FILENAME,O_RDONLY );
if(fd < 0)
{
perror("open");
_exit(-1);
}
#if 0
// 成功获取了stat结构体,从中可用获取属性信息了
// 2·2 的知识
printf("inode = %ld\n",buf.st_ino);
printf("File type and mode = %d\n",buf.st_mode);
printf("User ID of owner: %d\n",buf.st_uid);
#endif
#if 0
//----------------------------------------------------
// 判断文件属性
// 2·3 的知识
result = S_ISREG(buf.st_mode);
printf("result = %d\n",result);
#endif
#if 1
//----------------------------------------------------
// 文件权限测试
// 2·4 的知识
result = (buf.st_mode & S_IRUSR) >> 8;
printf("whether file ower has read pression :%d\n",result);
#endif
return 0;
}
结果:
inode = 22865
File type and mode = 33279
User ID of owner: 0
result = 1
”所以,这个文件就是普通文件。“
whether file ower has read pression :1
3· 文件权限管理
3·1 st_mode 中记录的文件权限位-----结合2·4的文件权限位掩码
(1)st_mode 本质上 是一个32 位的数(类型就是 unsigned int),这个数的每一个比特位标识一个含义。
(2)文件属性信息和文件的权限都记录在st_mode 中。我们用的时候使用专门的宏定义去得到文件属性信息,使用位掩码去取出相应的位即可得到相应的信息。
3·2 ls - l 可打印出权限列表
(1)xxx xxx xxx 一共9位,三个一组。第一组三个表示文件的属主(owner,user)对该文件的可读可写可执行权限;第二组3位表示文件的属主所在的组(group)对这个文件的权限;第三组3位表示其他用户(others)对这个文件的权限。
(2)属主就是这个文件属于谁,一般来说,属主就是创建这个文件的用户。但是一个文件创建后还可以用chowm命令去修改这个文件的属主;还可以用chgrp命令去修改这个文件属主所在的组。
3·3 文件操作时的权限检查规则
(1)一个程序a.out 被执行,a.out 中试图去操作一个文件1.txt,这时候如何判断a.out 是否具有对 1.txt的某种操作权限?
(2)判断方法:首先,1.txt 有9个权限位,规定了3种人(user,group,others)对它本身的操作权限。所以我们判定1.txt 是否可以被a.out 操作,关键先搞清楚a.out 对于1.txt来说到底算哪种人。准确的说是看a.out 是被谁执行,也就是当前程序(进程)是哪个用户的程序。
3·4 access 函数检查权限设置
(1)access函数可用测试得到当前执行的那个用户在当前那个环境下对目标文件是否具有某种操作权限。
int access(const char *pathname, int mode);
The mode specifies:
F_OK tests for the existence of the file.
R_OK, W_OK, and X_OK test whether the file exists and grants read, write, and execute permissions, respectively.
#include<stdio.h>
#include <unistd.h>
#define FILENAME "abc.txt"
int main (void)
{
int ret = -1;
ret = access(FILENAME,F_OK);
if(ret < 0)
{
perror("access");
_exit(-1);
}
else
{
printf("文件存在\n");
}
return 0;
}
结果:
文件不存在,因为我没有touch abc.txt
(2)chmod / fchmod 与权限修改
chmod是一个Linux命令,用来修改文件的各种权限属性。chmod命令只有root用户才有权力去执行修改。chmod命令内部是用Linux的一个叫chmod的API实现的。
可以man 1 chmod来查询chmode命令的用法。
(3)chown / fchown / lchown 与属主修改
(3)umask与文件权限掩码
文件掩码是Linux系统中维护的全局设置,umask的作用是用来设定我们系统中创建的文件的默认权限的。umask命令是umask 这个API实现的。
4· 读取目录文件
(1)opendir 函数 与 readdir 函数
opendir打开一个目录后会得到一个DIR类型的指针传给readdir使用。
readdir函数调用一次就会返回一个struct dirent类型的指针,这个指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。
readdir调用一次只能读出一个目录项,要想读出目录项中所有的目录项必须多次调用readdir函数。readdir函数内部会记住那个目录项已经被读过,哪个还没有读,所有多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示读完了所有目录项。
(2)可重入函数
有些函数是可重入的,有些函数是不可重入的,具体概念可以百度
readdir函数和我们前面接触的一些函数是不同的,首先readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir,但是readdir内部不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法是readdir不可重入的关键。
readdir在多次调用时是有关联的,这个关联也表明readdir函数是不可重入的。