Linux文件系统与基础IO

news2024/11/27 15:37:02

文章目录

  • 1 C文件接口
    • 1.1 `fopen`
    • 1.2 `fwrite`、`fread`、`rewind`、`fclose`
  • 2 文件系统调用
    • 2.1 `open`
      • 2.1.1 参数2:`flags`
      • 2.1.2 参数3:`mode`
      • 2.1.3 返回值——`file descriptor`
    • 2.2 write
    • 2.3 read
    • 2.4 close
  • 3 文件的本质
    • 3.1 `struct file`
    • 3.2 一个进程如何与多个文件相关联?
  • 4 重定向
    • 4.1 文件描述符对应的分配规则?
    • 4.2 `dup2`
    • 4.3 重定向`stdout`和`stderr`
  • 5 缓冲区
  • 6 硬盘(固态硬盘(SSD)/机械硬盘(磁盘))
    • 6.1 磁盘
    • 6.2 对磁盘的抽象
  • 7 如何理解目录
  • 8 软硬链接
    • 8.1 建立软连接
    • 8.2 建立硬链接
  • 9 动/静态库
    • 9.1 静态库
    • 9.2 动态库
      • 9.2.1 如何让可执行程序找到动态库
      • 9.2.2 动态库时怎么被加载的
      • 9.2.2 动态库时怎么被加载的

1 C文件接口

1.1 fopen

  • fopen新建的文件,如果是相对路径,在进程的工作路径下创建-
  • w:清空写入
  • a:追加

1.2 fwritefreadrewindfclose

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 int main() {
  5     FILE* f = fopen("bite.txt", "w+");
  6     const char* msg = "linux so easy\n";
  7     fwrite(msg, strlen(msg), 1, f);
  8 
  9     rewind(f);   //重置偏移量!!!                                                                                                         
 10     char buffer[strlen(msg)];
 11     fread(buffer, 1, strlen(msg), f);
 12     printf("%s\n", buffer);
 13     fclose(f);
 14 }

2 文件系统调用

2.1 open

//头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char* pathname, int flags);
int open(const char* pathname, int flags, mode_t mode);

2.1.1 参数2:flags

  1. O_RDONLY:只读
  2. 0_WRONLY: 只写
  3. O_CREAT:如果文件不存在,则创建文件到path路径下
  4. 0_TRUNC:打开的时候先清空(truncate)
  5. O_APPEND:在追加模式下打开,写入时在已有内容后追加

2.1.2 参数3:mode

  • umask:权限掩码:权限 & ~umask —> 最终权限(八进制, eg. 0xxx

  • umask系统调用改变umask

    • 头文件:<sys/types.h> <sys/stat.h>
    • ``mode_t umask(mode_t mask);`
    • 只改变当前进程的umask,不改变系统的, 进程里用自己进程的umask

2.1.3 返回值——file descriptor

  • 实质为一个数组下标(详细看3.2小节)

当调用write时,将fd传递给进程,进程根据files指针找到文件描述符表,然后由对应下标(fd)找到打开的文件file

  • 而C语言打开文件返回的FILE是C语言自己封装的结构体,里面一定含由文件描述符
cout << stdin->_fileno << endl;  //0
cout << stdout->_fileno << endl;  //1
cout << stderr->_fileno << endl;  //2

2.2 write

#include <unistd.h>

ssize_t write(int fd, const void* buf, size_t count);
  • 参数1:文件描述符
  • 参数2:写入内容
  • 参数3:写入内容的长度strlen(messsage)

2.3 read

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • 返回值
    • 大于0:返回读取的字节数
    • 0:写端关闭情况
    • -1:读取错误

2.4 close

3 文件的本质

3.1 struct file

操作系统维护一个被打开文件的信息:struct file, 包含:

  1. 在磁盘的什么位置
  2. 基本属性:权限,大小,读写位置,谁打开的
  3. 文件的内核缓冲区信息
  4. struct file* next指针,将不同文件链接起来

3.2 一个进程如何与多个文件相关联?

  • task_struct中含有一个stuct files_struct *files记录自己打开文件的信息,stuct files_struct *file里包含一个struct file *fd_array[]指针数组,存放文件指针(所以open时,会选择一个空的fd_array位置的下标返回)
  • struct file *fd_array[]文件描述符表,数组加标0、1、2分别指向三个默认打开的文件:stdin(键盘文件)stdout(显示器文件)stderr(显示器文件)

image-20231102134743325

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <string.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 
  8 int main() {
  9     const char* msg = "hello\n";
 10     write(1, msg, strlen(msg));   //想显示器写入
 11 
 12     char buffer[1024];
 13     ssize_t s = read(0, buffer, sizeof(buffer));   //向键盘读数据
 14     buffer[s] = '\0';                                                                                                                       
 15     printf("echo : %s\n", buffer);
 16     return 0;
 17 }

4 重定向

4.1 文件描述符对应的分配规则?

从0下标开始,寻找最小没有使用的数组位置

int main() {
    close(1);
    int fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0666);
    if (fd < 0) {
		perror("open");
        return 1;
    }
    const char *msg = "hello\n";
   	for (int i = 0; i < 5; i++) {
        //因为关闭了1,open文件之后占用1这个位置,写入从显示器重定向到了文件中
        write(1, msg, strlen(msg));    
    }
    close(fd);
}

4.2 dup2

#include <unistd.h>

int dup2(int oldfd, int newfd)   //makes newfd be the copy of oldfd      

重定向:将文件描述符对应下标的指针拷贝到要重定向的文件的位值的指针

  • fd_array[oldfd]拷贝到fd_array[newfd], 拷贝之后需要close(oldfd);

4.3 重定向stdoutstderr

int mian() {
   	fprintf(stdout, "normal msg");
    fprintf(stdout, "normal msg");
    fprintf(stdout, "normal msg");
    
    fprintf(stderr, "error msg");
    fprintf(stderr, "error msg");
    fprintf(stderr, "error msg");
}
//gcc test.c -o test
  • ./test > normal.log:normal msg重定向到normal.log, error msg打印到屏幕

stdoutstderr都重定向到一个文件all.log

  1. ./test &>all.log
  2. ./test >&all.log
  3. ./test >all.log 2>&1
  4. ./test 2>all.log 1>all.log

5 缓冲区

  • C的输出接口输出到用户级缓冲区(该缓冲区不在系统中)

  • 显示器的文件的刷新方案是行刷新,所以在printf执行完成遇到\n就会将数据进行刷新

  • 缓冲区刷新策略:

    • 无缓冲——直接刷新
    • 行缓冲——碰到\n刷新 —— 显示器
    • 全缓冲——缓冲区满了才刷新 —— 文件写入
    • 进程退出
  • fprintf/fwrite等向用户级缓冲区中写入,当缓冲区刷新时调用write系统调用接口(因此,C中fflush函数一定封装了write),write向系统级缓冲区中写入

  • 为什么要有用户级的缓冲区

    • 解决效率问题
    • 配合格式化
  • 用户及的缓冲区在哪里?—— 存在FILE结构体中,

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <string.h>
  4 
  5 int main() {
  6     const char* fstr = "hello fwrite\n";
  7     const char* str = "hello write\n";
  8 
  9     printf("hello printf, pid:%d, ppid:%d\n", getpid(), getppid());
 10     fprintf(stdout, "hello fprintf, pid:%d, ppid:%d\n", getpid(), getppid());
 11     fwrite(fstr, strlen(fstr), 1, stdout);
 12                       
 13     write(1, str, strlen(str));
 14 
 15     fork();
 16 
 17 }

image-20231104152320757

write为系统调用接口,直接刷新,而由于重定向输出到文件,用户级缓冲区的刷新策略更改为全缓冲,fork后子进程写时拷贝 ,而缓冲区也会随着FILE结构体的拷贝而拷贝,当子进程退出后刷新缓冲区,接着父进程退出也刷新缓冲区

  • FILE结构体:
/usr/include/libio.h
struct _IO_FILE {
 int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
 //缓冲区相关
 /* The following pointers correspond to the C++ streambuf protocol. */
 /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
 char* _IO_read_ptr; /* Current read pointer */
 char* _IO_read_end; /* End of get area. */
 char* _IO_read_base; /* Start of putback+get area. */
 char* _IO_write_base; /* Start of put area. */
 char* _IO_write_ptr; /* Current put pointer. */
 char* _IO_write_end; /* End of put area. */
 char* _IO_buf_base; /* Start of reserve area. */
 char* _IO_buf_end; /* End of reserve area. */
 /* The following fields are used to support backing up and undo. */
 char *_IO_save_base; /* Pointer to start of non-current get area. */
 char *_IO_backup_base; /* Pointer to first valid character of backup area */
 char *_IO_save_end; /* Pointer to end of non-current get area. */
 struct _IO_marker *_markers;
 struct _IO_FILE *_chain;
 int _fileno; //封装的文件描述符
#if 0
 int _blksize;
#else
 int _flags2;
#endif
 _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
 /* 1+column number of pbase(); 0 is unknown. */
 unsigned short _cur_column;
 signed char _vtable_offset;
 char _shortbuf[1];
 /* char* _save_gptr; char* _save_egptr; */
 _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

6 硬盘(固态硬盘(SSD)/机械硬盘(磁盘))

  • 磁盘上存储的文件 = 文件的内容 + 文件的属性
  • 文件内容——数据块, 文件属性 —— inode
  • 文件在磁盘当中的存储是将属性和内容分开存储的

6.1 磁盘

定位一个扇区:面(定位该用哪个磁头) -> 磁道(柱面) -> 扇区 (CHS寻址方式)

  • 时间消耗主要来自于寻道时间

6.2 对磁盘的抽象

LBA地址:将磁盘磁头、磁道、扇区逻辑抽象成一个一维数组,通过除模运算计算出CHS

09B31BEA48DF0457251FF93A6F55B0A6

  • 建立联系,

  • 在Linux中,用于标识文件, 找到inode编号->inode table -> struct inode -> blocks[] -> 文件内容

  • struct inode {
        inode number
        //文件类型
        //权限 : w/r/x
        //引用计数
        //拥有者
        //所属组
        //ACM时间
        int blocks[N]    //
    }
    
  • inode table: 存放inode, 每个inode有唯一的编号(一个文件一个inode, 一个inode可能对应多个block

    • ls -li: 查看inode编号
  • Block Bitmap:位图,标记块是否被使用

  • inode Bitmap:位图,标记inode编号是否是有效的

  • Group Descriptor Table

  • Super Block:文件系统的基本信息,包含整个分区的基本使用情况

    • 一共有多少个组、每个组的大小,每个组inode的数量、每个组的block数量、每个组的其实inode、文件系统的类型和名称

7 如何理解目录

  • 目录是文件:内容 + 属性,也有inode

  • 目录也有数据块,存放目录下,文件的文件名和对应文件与inode的映射关系

    • 因此同一目录下不能有相同文件名

    • 若该目录没有w权限,无法创建文件:因为无法将文件名与inode写入该目录的数据块

    • 若该目录没有r权限,无法查看该目录

    • 若该目录没有x权限,无法进入该目录

  • dentry缓存

    • 如何知道自己的inode?当前的目录的数据块中存放当前目录下文件名与inode的映射关系,而当前目录又被上级目录视为文件,存放该目录的inode与数据块,所以当访问一个文件的inode时需要递归到根目录再从根目录访问到当前inode

8 软硬链接

8.1 建立软连接

ln -s file.txt soft-link

image-20231107214116494

  • 软连接具有独立的inode,也有独立的数据块,它的数据块里面保存的是指向文件的路径(类似于快捷方式)

8.2 建立硬链接

ln test.txt hard-link

image-20231107214049062

  • 硬链接具有相同的inode,本质上是在当前目录下,建立新的文件名字与inode链接(取别名/引用)
  • 不允许给目录建立硬链接(除非是 ...),不然会造成查找路径的环路问题

9 动/静态库

  • 静态库:libXXX.a
  • 动态库:libXXX.so

9.1 静态库

  • 静态库本质上时一些.o文件的集合
  • ar是gun归档工具, 用于打包静态库rc表示replace and create
lib=libmymath.a

$(lib):mymath.o     //可能有多个.o文件
	ar -rc $@ $^
mymath.o:mymath.c
	gcc -c $^
	
.PHONY:
clean:
	rm -f *.a *.o
	
.PHONY:output
output:
	mkdir -p lib/include
	mkdir -p lib/mymathlib
	cp *.h lib/include
	cp *.a lib/mymathlib
	

使用库:

  1. 找到头文件路径 —— -I
  2. 找到库的路径(否则链接时报错)—— -L
  3. 并且说明链接该路径下的哪一个库 —— -l (去掉lib,去掉.a,剩下的名字) ;第三方库必须指定库名称
gcc main.c -I ./lib/include/ -L ./lib/mymathlib/ -lmymath
  • 查看可执行文件 所用的标准库(动态库)
ldd a.out
  • 库的安装
  1. 拷贝到指定目录
sudo cp lib/include/math.h /usr/include/
sudo cp lib/mymathlib/libmymath.a /lib64/ 
  1. 建立软连接(不建议这么做)

9.2 动态库

  1. 生成.o文件
gcc -fPIC -c mylob.c

(-c 不知名目标文件时,生成的时同名.o文件)

  1. 生成.so文件
gcc -shared -o libmymethod *.o

(不加-shared生成的是可执行文件)

  • 当程序运行动态库中的方法,系统会将动态库加载到内存中执行,所以.so文件自动带有x可执行权限
dy-lib=libmymethod.so
static-lib=libmymath.a

.PHONY:all
all: $(dy-lib) $(static-lib)

$(static-lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.c
	gcc -c $^

$(dy-lib):mylog.o myprint.o
mylog.o:mylog.c
	gcc -fPIC -c $^
myprint.o:myprint.c
	gcc -fPIC -c $^
	
.PHONY:clean
clean:
	rm -rf *.o *.a *.so mylib
   
.PHONY:output
output:
	mkdir -p mylib/include
	mkdir -p mylib/lib
	cp *.h mylib/include
	cp *.a mylib/lib
	cp *.so mylib/lib
  • 编译时于静态库相同
  • -fPIC:与地址无关码

9.2.1 如何让可执行程序找到动态库

IMG_2827

四种方法:

  1. 将动态库拷贝到/lib64
  2. 建立在/lib64下的软连接
ln -s xxx(绝对路径) /lib64/xxx
  1. 添加到环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xxx/xxxx/xx(绝对路径)
    • cd /etc/ld.so.conf.d
    • 创建一个.conf文件
    • 将动态库路径添加到该文件中
    • 执行ldconfig

9.2.2 动态库时怎么被加载的

  • 动态库在系统中加载后,会被所有进程共享

  • 共享库中的全局变量,既然会被共享,那么会不会冲突? 不会,因为会发生写时拷贝

  • 程序在编译好之后,内部有地址,及就是虚拟地址,编译器也要考虑程序内存加载的问题

  • 共享库肯能非常大,所以使用固定位置是不现实的,库可以在虚拟内存的共享区中任意位置加载, 动态库内部的函数不采用绝对编址,只需要表示每个函数在库中的偏移量即可, 通过库的起始地址 + 偏移量找到函数

    • 所以编译形成动态库的链接文件(.o)时,需要带选项-fPIC:(position independent code)
      s xxx(绝对路径) /lib64/xxx

3. 添加到环境变量

```bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xxx/xxxx/xx(绝对路径)
    • cd /etc/ld.so.conf.d
    • 创建一个.conf文件
    • 将动态库路径添加到该文件中
    • 执行ldconfig

9.2.2 动态库时怎么被加载的

  • 动态库在系统中加载后,会被所有进程共享

  • 共享库中的全局变量,既然会被共享,那么会不会冲突? 不会,因为会发生写时拷贝

  • 程序在编译好之后,内部有地址,及就是虚拟地址,编译器也要考虑程序内存加载的问题

  • 共享库肯能非常大,所以使用固定位置是不现实的,库可以在虚拟内存的共享区中任意位置加载, 动态库内部的函数不采用绝对编址,只需要表示每个函数在库中的偏移量即可, 通过库的起始地址 + 偏移量找到函数

    • 所以编译形成动态库的链接文件(.o)时,需要带选项-fPIC:(position independent code)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1296039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

倒计时模块复习

经典回顾倒计时 倒计时的基本布局介绍。 一个内容区域和一个输入区域&#xff0c;内容区域进行划分 直接使用flex布局会更快一点。 js代码 我们利用一下模块化思想&#xff0c;直接把获得时间这个功能写成一个函数。方便后续的调用 function getTime() {const date new Date…

使用pytorch查看中间层特征矩阵以及卷积核参数

这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 1和4是之前讲过的alexnet和resnet模型 2是分析中间层特征矩阵的脚本 3是查看卷积核参数的脚本 1设置预处理方法 和图像训练的时候用的预处理方法保持一致 2实例化模型 3载入之前的模型参数 4载入…

智能优化算法应用:基于驾驶训练算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于驾驶训练算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于驾驶训练算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.驾驶训练算法4.实验参数设定5.算法结果6.参考…

带大家做一个,易上手的家常辣子鸡

先从冰箱拿出鸡肉解冻 拿小半根葱 去掉最外面一层皮 切成小段 最备好 花椒 干辣椒 准备四五个大料 起锅烧油 这道菜需要放其他菜两到三倍的油 油温上来之后 放入干辣椒和花椒进行翻炒 等它们都烧黑之后捞出来 这样 辣味就留在油里面了 然后 倒入鸡肉 葱段 大料 然后 倒…

从0到1,手把手带你开发截图工具ScreenCap------001实现基本的截图功能

ScreenCap---Version&#xff1a;001 说明 从0到1&#xff0c;手把手带你开发windows端的截屏软件ScreenCap 当前版本&#xff1a;ScreenCap---001 支持全屏截图 支持鼠标拖动截图区域 支持拖拽截图 支持保存全屏截图 支持另存截图到其他位置 GitHub 仓库master下的Scr…

如何排查rpc mount export: RPC: Timed out问题

文章目录 问题描述查看nfs服务是否运行正常如果以上都通过,尝试下面步骤 问题描述 我们将讨论您在 NFS 客户端上看到的 NFS 错误之一的故障排除。在尝试与 NFS 相关的命令时可以看到此错误&#xff0c;如下所示&#xff1a; 通常&#xff0c;当您看到此错误时&#xff0c;您也…

整合消息队列RabbitMQ

为什么使用消息队列MQ&#xff1f; 因为使用消息队列有多个好处&#xff1a;可以实现系统服务的解耦、异步和削峰&#xff1a; 异步通信&#xff1a;消息队列提供了一种异步通信的方式&#xff0c;发送方可以将消息发送到队列中&#xff0c;然后继续执行其他任务&#xff0c;…

vue使用甘特图dhtmlxgantt + gantt.addTaskLayer

效果图&#xff1a; 甘特图 官网地址 gantt安装与使用 vue版---部分功能收费 安装gantt 或 引入文件 npm install dhtmlx-gantt -save或import gantt from "/public/static/dhtmlxgantt/dhtmlxgantt.js"; import "/public/static/dhtmlxgantt/locale/local…

Pytest+Yaml+Excel 接口自动化测试框架的实现示例

一、框架架构 二、项目目录结构 三、框架功能说明 解决痛点&#xff1a; 通过session会话方式&#xff0c;解决了登录之后cookie关联处理框架天然支持接口动态传参、关联灵活处理支持Excel、Yaml文件格式编写接口用例&#xff0c;通过简单配置框架自动读取并执行执行环境一键…

python3.5安装教程及环境配置,python3.7.2安装与配置

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python3.5安装教程及环境配置&#xff0c;python3.7.2安装与配置&#xff0c;现在让我们一起来看看吧&#xff01; python 从爬虫开始&#xff08;一&#xff09; Python 简介 首先简介一下Python和爬虫的关系与概念&am…

深度学习实战65-人脸检测模型LFFD的搭建,LFFD模型的架构与原理的详细介绍

大家好,我是微学AI,今天给大家介绍一下深度学习实战65-人脸检测模型LFFD的搭建,LFFD模型的架构与原理的详细介绍。LFFD(Light and Fast Face Detector)模型是一种用于人脸检测的深度学习模型,其设计旨在实现轻量级和快速的人脸检测。本文将详细介绍LFFD模型的定义、优点、原…

类人智能体概念、能力与衍生丨AI Agents闭门研讨观点集锦

导读 在智源社区举办的「青源Workshop第27期&#xff1a;AI Agents 闭门研讨会」上&#xff0c;来自英伟达的高级应用科学家王智琳、CAMEL一作李国豪、AutoAgents一作陈光耀&#xff0c;以及相关技术专家们共同参与交流讨论&#xff0c;分享了最新的研究成果&#xff0c;共同探…

人工麝香市场分析:中国市场年需求量超过15吨

人工麝香作为濒危动物药材麝香的替代品&#xff0c;等同天然麝香配方使用。 是国家重大科研成果和保密品种&#xff0c;用人工麝香生产中成药品种近400种&#xff0c;涵盖中成药常用剂型。 是珍稀动物药材代用品研究的重大突破&#xff0c;为其它珍稀动物药材的应用开辟了一条重…

金融量化交易:使用Python实现遗传算法

大家好&#xff0c;遗传算法是一种受自然选择过程启发的进化算法&#xff0c;用于寻找优化和搜索问题的近似解决方案。本文将使用Python来实现一个用于优化简单交易策略的遗传算法。 1.遗传算法简介 遗传算法是一类基于自然选择和遗传学原理的优化算法&#xff0c;其特别适用…

【方法】Excel表格的“限制保护”不想要了,如何取消?

我们知道&#xff0c;Excel表格可以设置“限制保护”&#xff0c;保护文件不被随意更改&#xff0c;那如果后续不需要保护了&#xff0c;如何取消呢&#xff1f; 下面小编来说说Excel表格常用的三种“保护”&#xff0c;是如何取消的。 第一种&#xff0c;Excel表格的工作表或…

第15章:随堂复习与企业真题(File类与IO流)

第15章&#xff1a;随堂复习与企业真题&#xff08;File类与IO流&#xff09; 一、随堂复习 1. File类的使用 File类的一个实例对应着磁盘上的一个文件或文件目录。 ----> “万事万物皆对象”&#xff08;熟悉&#xff09;File的实例化、常用的方法File类中只有新建、删除…

Unity 自定义窗口

放在Editor文件夹下&#xff1b; #if UNITY_EDITORusing System; using UnityEditor; using UnityEngine;namespace EditorCustumTool {/// <summary>/// 自定义窗口/// </summary>public class CustomWindow : EditorWindow{public enum FlagType{Flag1 101,Fl…

Qt内存管理、UI编辑器、客制化组件、弹出对话框、常用部件类

头文件的小技巧 #include <QtWidgets> // 在自动生成的 .h 里面加上此句 适用条件&#xff1a; QT 的内存管理 当父窗体被关闭时&#xff0c;子部件的内存会自动释放。 对象树是一种管理对象生命周期的机制。当一个对象被添加到另一个对象的子对象列表中时&#xff0…

Springboot+AOP+注解实现字段AES+Base64加解密

AOP实现AESBASE64加解密 场景如下&#xff1a; 需要对数据库存储的字段&#xff0c;进行加解密的处理。如果都直接写代码的话&#xff0c;那么代码回冗余很多&#xff0c;所以使用AOP注解去实现。让代码简洁&#xff0c;方便 具体实现如下&#xff1a; 1、依赖 <depende…

C语言搭建项目-学生管理系统(非链表)

、 目录 搭建offer.h文件 搭建offer.c中的main函数 密码登入系统 搭建my_oferr.c中的接口函数 使用帮助菜单接口函数 增加学生信息接口函数 查询学生信息接口函数 删除学生信息接口函数 保存学生信息接口 打开文件fopen 关闭文件fclose 判断是否保存文件fwrite 退出执行文件…