自学嵌入式第N天(Linux篇——文件编程)

今天是文件夹的操作,主播感觉自己学懵了,希望写完这一篇能给自己理明白。

一、基础操作

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对文件打开,读写,关闭的操作,以及读写指针的定位,和文件夹的参数。也不算难,就是记忆的东西比较多,有时间的话可以好好背一下。

相关推荐
IT_陈寒1 小时前
Vite的热更新突然失效,原来我忽略了这个配置
前端·人工智能·后端
怪奇云呼军1 小时前
闪电智能VoiceAgent 如何管理呼入、接听、桥接和挂断状态?
java·前端·网络·数据库·人工智能
云浪1 小时前
Milvus + RAG 实战:《红楼梦》问答助手
前端·人工智能·后端
Escalating_xu1 小时前
【Linux】进程间通信:从匿名管道、FIFO 到共享内存、消息队列与信号量
java·linux·面试
恋猫de小郭1 小时前
Dart 3.13 大更新,感觉比 Flutter 更带劲
android·前端·flutter
晓得迷路了1 小时前
栗子前端技术周刊第 142 期 - DeepSeek Harness、pnpm 12 RC、crypto‑js...
前端·javascript·ai编程
IT机器猫1 小时前
RabbitMQ基础二
java·spring boot·分布式·spring cloud·log4j·rabbitmq·springamqp
xiaoxiangsiyan1 小时前
RHCE之2026年全套考点详解
运维·前端·网络·chrome·学习·rhce
caimouse2 小时前
ReactOS 图形系统分析(33):字体子系统 — font.c
c语言·开发语言·reactos