今天是文件夹的操作,主播感觉自己学懵了,希望写完这一篇能给自己理明白。
一、基础操作
1.打开opendir
头文件:#include <sys/types.h>,#include <dirent.h>
形式:DIR *opendir(const char *name);
参数:name要打开的文件夹
返回值:成功时返回文件夹的流指针,指向第一个文件;
失败时返回NULL,errno会被设置
2.关闭closedir
头文件:#include <sys/types.h>,#include <dirent.h>
形式:int closedir(DIR *dirp);
参数:要关闭的目录(这里要写opendir的返回值)
返回值:成功时返回0,失败时返回-1,errno会被设置
注意:不要多次释放。
3.读readdir(文件夹只能读,不能写)
头文件:#include <sys/types.h>,#include <dirent.h>
形式:struct dirent *readdir(DIR *dirp);
参数:要读的目录(这里要写opendir的返回值)
返回值:成功时返回一个结构体指针,失败时返回NULL,errno会被设置。
这里要注意返回的截个结构体的内容

d_ino是文件真正的本体编号,系统内核靠 inode 管理文件所有底层信息,一个 inode 里面保存着: 文件权限、大小、硬盘数据存储位置、硬链接计数、创建 / 修改时间、属主 uid/gid 等全部属性 stat结构体里的 st_ino 和这里的 d_ino 是同一个数字。
d_type表示文件的类型:
| d_type 宏 | 含义 | st_mode 提取的类型宏 |
|---|---|---|
| DT_REG | 普通文件 | S_IFREG |
| DT_DIR | 文件夹 | S_IFDIR |
| DT_LNK | 软链接 | S_IFLNK |
| DT_CHR | 字符设备 | S_IFCHR |
| DT_BLK | 块设备 | S_IFBLK |
| DT_FIFO | 有名管道 | S_IFIFO |
| DT_SOCK | 套接字 | S_IFSOCK |
d_name是正在读的文件的名字。
二、进阶操作
1.chdir
头文件:#include <unistd.h>
形式:int chdir(const char *path);
功能:改变当前程序的工作路径
参数:path改变到的路径
返回值:成功时返回0,失败时返回-1
例子:


这里可以看到工作路径改变了,我们就可以在一个代码中,在不同位置创建文件夹或者文件。
2.getcwd
头文件:#include <unistd.h>
形式:char *getcwd(char *buf, size_t size);
功能:改变当前程序的工作路径
参数:buf用来保存工作路径的首地址,size用来保存保存路径空间的长度
返回值:成功时返回包含路径空间的字符串首地址(就是buf),失败时返回NULL.
3.mkdir
头文件: #include <sys/stat.h>,#include <sys/types.h>
形式: int mkdir(const char *pathname, mode_t mode);
功能:创建一个目录
参数:pathname目录名,mode目录的模式(这个在将stat函数的时候详细讲)
返回值:成功时返回0,失败时返回-1
4.stat
头文件: #include <sys/types.h>, #include <sys/stat.h>,#include <unistd.h>
形式:int stat(const char *pathname, struct stat *statbuf)
功能:创建一个目录
参数:pathname目录名,mode目录的模式(这个在将stat函数的时候详细讲)
返回值:成功时返回0,失败时返回-1

| 字段 | 解释 |
|---|---|
st_dev |
文件所在的设备(分区)ID |
st_ino |
inode 号(文件在分区里的身份证) |
st_mode |
类型 + 权限(16 位位运算) |
st_nlink |
硬链接数 |
st_uid |
所有者用户 ID |
st_gid |
所属组 ID |
st_rdev |
设备文件的设备号(普通文件忽略) |
st_size |
文件逻辑大小(字节) |
st_blksize |
文件系统 I/O 块大小(一般 4096) |
st_blocks |
实际占用的 512B 块数 |
st_atime |
最后访问时间 |
st_mtime |
最后修改时间(ls -l 显示的) |
st_ctime |
最后状态改变时间 |
可以通过形参的结构体变量来访问这个文件的参数。
·st_mode
这里面最复杂的就是st_mode,它是由16位二进制组成,0-3位代表文件类型,4-6位代表特殊权限区,7-9位是所有者权限,10-12位是所属组权限,13-15是其他人权限。那我们怎么能分别拿到他的文件类型以及各种权限呢?
我们将st_mode&S_IFMT就可以让文件类型位保持不变,其余位均位0,然后再通过switch,case进行比较就可以拿到对应的类型是什么。
| 常量名 | 八进制值 | 16 位二进制 | 高 4 位 | 含义 | 打印字符 |
|---|---|---|---|---|---|
S_IFMT |
0170000 |
1111 0000 0000 0000 |
1111 |
类型掩码(抠类型用的筛子) | --- |
S_IFSOCK |
0140000 |
1100 0000 0000 0000 |
1100 |
套接字 socket | s |
S_IFLNK |
0120000 |
1010 0000 0000 0000 |
1010 |
符号链接 | l |
S_IFREG |
0100000 |
1000 0000 0000 0000 |
1000 |
普通文件 | - |
S_IFBLK |
0060000 |
0110 0000 0000 0000 |
0110 |
块设备 | b |
S_IFDIR |
0040000 |
0100 0000 0000 0000 |
0100 |
目录 | d |
S_IFCHR |
0020000 |
0010 0000 0000 0000 |
0010 |
字符设备 | c |
S_IFIFO |
0010000 |
0001 0000 0000 0000 |
0001 |
管道 FIFO | p |

这个特殊权限不常用就不说了。
| 常量名 | 八进制值 | 16 位二进制 | 所在位 | 含义 |
|---|---|---|---|---|
S_ISUID |
0004000 |
0000 1000 0000 0000 |
bit11 | 执行时临时变成文件所有者 |
S_ISGID |
0002000 |
0000 0100 0000 0000 |
bit10 | 执行时临时变成文件所属组 |
S_ISVTX |
0001000 |
0000 0010 0000 0000 |
bit9 | sticky 粘滞位(如 /tmp 目录) |
所有者权限有三位,从左到右为读,写,执行三个权限,和模式一样,我们将st_mode&S_IRUSR如果为1,说明所有者有读的权限,依次类推便可拿到所有者,所属组,其他用户都有什么权限。
| 常量名 | 八进制值 | 16 位二进制 | 所在位 | 含义 |
|---|---|---|---|---|
S_IRWXU |
00700 |
0000 0001 1100 0000 |
bit8~6 | 所有者权限掩码(rwx 三位全 1) |
S_IRUSR |
00400 |
0000 0001 0000 0000 |
bit8 | 所有者有读权限 |
S_IWUSR |
00200 |
0000 0000 1000 0000 |
bit7 | 所有者有写权限 |
S_IXUSR |
00100 |
0000 0000 0100 0000 |
bit6 | 所有者有执行权限 |
| 常量名 | 八进制值 | 16 位二进制 | 所在位 | 含义 |
|---|---|---|---|---|
S_IRWXG |
00070 |
0000 0000 0011 1000 |
bit5~3 | 组权限掩码(rwx 三位全 1) |
S_IRGRP |
00040 |
0000 0000 0010 0000 |
bit5 | 组有读权限 |
S_IWGRP |
00020 |
0000 0000 0001 0000 |
bit4 | 组有写权限 |
S_IXGRP |
00010 |
0000 0000 0000 1000 |
bit3 | 组有执行权限 |
| 常量名 | 八进制值 | 16 位二进制 | 所在位 | 含义 |
|---|---|---|---|---|
S_IRWXO |
00007 |
0000 0000 0000 0111 |
bit2~0 | 其他人权限掩码(rwx 三位全 1) |
S_IROTH |
00004 |
0000 0000 0000 0100 |
bit2 | 其他人有读权限 |
S_IWOTH |
00002 |
0000 0000 0000 0010 |
bit1 | 其他人有写权限 |
S_IXOTH |
00001 |
0000 0000 0000 0001 |
bit0 | 其他人有执行权限 |

前面一篇说到open和mkdir这两个函数,其实他有两种形式
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode); int mkdir(const char *pathname, mode_t mode);
这里的模式和这里的模式是一样的,有所有者,所属组,其他人的权限,每个三位,分别为
读权限,写权限,运行权限,已知3位二进制对应1位8进制,所以我们可以给open的模式写为0666,代表大家都能读和写,但是我们真的这么写之后发现文件的权限为0644,这是因为你的系统为了安全,将你给的权限&~(umask),umask是022,&之后的结果为0644,让用户统一控制所有程序创建的文件权限,防止程序创建权限过大的文件。所以在open时如果是创建普通文件给0666即可,创建可执行文本才给0777。
而对于文件夹就必须包含可执行为x,因为没有x就没办法进入这个文件夹,都进不去文件夹了,就没办法在这个文件夹里面创建文件了,所以一般mkdir时给0777。
二、Linux文件基础知识
1.文件构成
Linux系统中一个文件由目录项(struct dirent)、inode表和数据块组成。
目录项:包括文件名和inode节点号
Inode表:包含文件的一些信息。例如,inode号,文件类型,文件大小等。
数据块:文件具体内容存放的地方。
当我们查看一个文件的时候,首先根据文件名,找到我们目录项中的inode号,通过inode号进入我们inode表中,查找到该文件中一些信息。然后通过inode表中的保存的数据区的指针,读取我们相应数据区的内容。

2.硬链接(本质上就是给文件起了个别名)
Linux系统中规定,只有在文件的打开次数为0(即文件这个时候没有打开),并且文件的硬连接数为0,此时文件才会被删除,硬链接与源文件直接关联。修改一个,另一个同时被修改。删除一个另一个不会有影响。
特点:不占用硬盘空间,不能对目录操作,不能跨文件系统。
命令:ln 源文件名 硬链接文件名

3.软链接(类似于我们windows的快捷方式,用来记录我们目标的路径)
特点:占用磁盘空间,可以对目录操作,可以跨文件系统。
命令:ln -s 源文件 软链接文件

硬链接和软链接的区别:
(1)硬链接原文件和新文件的inode编号一致。而软链接不一样。
(2)对原文件删除,会导致软链接不可用,因为软连接存储是路径,而硬链接不受影响
4.常用函数
(1)struct passwd *getpwuid(uid_t uid);

可以uid编号转化为文件所有者名,getpwuid(uid_t uid)->pw_name;
(2)struct group *getgrgid(gid_t gid);

将gid转化为组名。
文件编程就这么多东西,简单来说就是标准IO,文件IO对文件打开,读写,关闭的操作,以及读写指针的定位,和文件夹的参数。也不算难,就是记忆的东西比较多,有时间的话可以好好背一下。