【Linux基础I/O】文件调用接口、文件描述符、重定向和缓冲区

【Linux基础I/O一】文件描述符和重定向

  • 1.C语言的文件调用接口
  • 2.操作系统的文件调用接口
    • 2.1open接口
    • 2.2close接口
    • 2.3write接口
    • 2.4read接口
  • 3.文件描述符fd的本质
  • 4.标准输入、输出、错误
  • 5.重定向
    • 5.1什么是重定向
    • 5.2输入重定向和输出重定向
    • 5.3系统调用的重定向dup2
  • 6.缓冲区

1.C语言的文件调用接口

  1. fopen
FILE *fopen(const char *filename, const char *mode);

filename 参数是一个字符串,指定要打开的文件名或路径
mode 参数是一个字符串,指定文件的打开模式,常见如下:
“r”:只读,若文件不存在则报错
“w”:只写,若文件不存在则创建,打开时清空文件原有内容
“a”:只写,若文件不存在则创建,打开时从文件末尾追加
返回值:
如果成功打开文件,则返回指向 FILE 类型结构的指针,该指针用于后续的文件操作。
如果打开失败,返回 NULL,并且通过检查 errno 变量可以确定失败的具体原因

FILE *fp = fopen("temp.txt", "r");
if (fp == NULL) {perror("Error opening file");return 1;
}
  1. fclose
int fclose(FILE *stream);

stream 是一个指向 FILE 结构的指针,指定要关闭的文件
返回值:
如果成功关闭文件,则返回 0。
如果关闭失败,则返回 EOF

FILE *fp = fopen("temp.txt", "r");
if (fp == NULL) {perror("opening error");return 1;
}if (fclose(fp) == 0) {printf("close succeed.\n");
} else {perror("closing error");return 1;
}
  1. fprintf
int fprintf(FILE *stream, const char *format, ...);

stream是一个指向FILE结构的指针,指定要写入的目标文件
format是一个格式化字符串,类似于printf函数中的格式化字符串,用于指定输出的格式
返回值:
成功返回写入的字符数,如果出错则返回一个负数
默认打开文件的时候,清空文件内容
a打开方式:append追加方式写入文件,不会清空原文件内容

2.操作系统的文件调用接口

2.1open接口

在这里插入图片描述

pathname 是一个字符串,表示要打开的文件路径
flags 是打开文件的标志位,例如 O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(若打开的文件不存在,则创建该文件)
mode 是文件的权限,通常与 flags 参数中的某些标志结合使用,用于指定文件的创建模式
返回值:
如果成功,返回一个新的文件描述符,用于后续的文件操作
如果出错,返回 -1

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT);return 0;
}

在这里插入图片描述
运行./mybin后,当前目录就出现了文件log.txt了,但是它的权限值是乱码-r-s–x–T,如果你删掉该文件后再次运行代码,你会发现下一次的权限值和上次还不一样
此时就需要三个参数的open接口:
mode用于控制文件的初始权限,一般系统默认掩码是0002

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);return 0;
}

在这里插入图片描述
open的第三个参数传入0666,也就是log.txt的初始权限
由于umask是0002,所以最终权限为664也就是rw-rw-r–

2.2close接口

在这里插入图片描述

作用:关闭文件
描述符fd对应的文件, 调用成功返回0

2.3write接口

在这里插入图片描述

fd:被写入文件的fd
buf:指向被写入的字符串
count:写入字符的个数

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);char* str = "Hello\n Hello\n";write(fd, str, 6);close(fd);return 0;
}

向log.txt写入了一个字符串str,write的第三个参数为6,只写入了6个字符Hello\n,输出结果是Hello
在这里插入图片描述
在保留原先log.txt的情况下,更改test.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);char* str = "Hello\n Hello\n";write(fd, str, 6);close(fd);return 0;
}

在这里插入图片描述
log.txt的内容变成了123lo,为什么?

以O_WRONLY模式对文件进行写入时,不会先把文件内容清空,而是直接从头开始覆盖

有两种解决方案,对应两个open的选项

  1. O_TRUNC打开时清空文件内容
  2. O_APPEND以追加的形式写入

2.4read接口

在这里插入图片描述

fd:目标文件的文件描述符fd
buf:将文件内容读取到buf指向的空间中
count:最多读取count个字节的内容
返回值:
< 0:读取发送错误
= 0:读取到文件末尾
0:读取成功,返回读取到的字符个数

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>int main()
{int fd = open("log.txt", O_RDONLY);char buffer[1024];ssize_t ret1 = read(fd, buffer, 1024);printf("ret1 = %ld\n", ret1);printf("%s", buffer);close(fd);return 0;
}

在系统创建一个log.txt文件,内容为字符串hello Linux
一开始用open以只读RDONLY形式打开文件,通过read(fd, buffer, 1024)把内容存储到数组buffer中,并把返回值交给ret1,随后输出ret1和buffer
在这里插入图片描述
第一次read返回值为12,也就是字符串Hello Linux有12个字符

3.文件描述符fd的本质

文件描述符的本质是一个数组的下标

在Linux系统下,一切皆文件
文件 = 内容 + 属性
文件操作 = 对内容的操作 或 对属性的操作
因为冯诺依曼体系结构,CPU只和内存做交互,所以要对文件做修改就需要加载到内存
我们会同时打开多个文件,也会有别人同时打开文件,所以,操作系统需要管理这些打开的文件
管理 = 先描述,再组织
操作系统同样会像管理进程那样,也给文件创建对应的结构体,然后文件之间会有一些连接关系
这样,对文件的管理就变成对某种数据结构的管理
文件操作是用户让操作系统进行的,操作系统会为此创建进程
所以文件操作实质是进程和被打开文件的关系

操作系统运行时,会有很多进程在运行
在文件没有被打开之前,文件是存在磁盘中的
打开文件是进程打开的:进程将文件的数据加载到文件内核级的缓存块中
而一个进程能打开很多文件,同时,系统当中可以存在许多进程
为了更好的管理文件,所有被打开的文件,操作系统都会对其创建一个结构体struct file在这里插入图片描述
文件 = 属性 + 内容,而这个struct file结构体对象就是用来描述被打开的文件
被打开的文件结构体对象,被操作系统用双向链表组织起来,成为一个双向链表
于是,操作系统对被打开文件的管理就变成了对一个双向链表的增删查改,解决了对文件的管理问题

文件和进程之间的关系如何描述和组织
进程的PCB(task_struct)结构体对象中存在一个指针变量:struct files_struct *file
在Linux 2.6.10内核中,struct files_struct如下:
其最后一个成员fd_array是一个数组,指向的成员类型为struct file*,也就是指向struct file的指针

struct files_struct {atomic_t count;spinlock_t file_lock;/* Protects all the below members.  Nests inside tsk->alloc_lock */int max_fds;int max_fdset;int next_fd;struct file ** fd;/* current fd array */fd_set *close_on_exec;fd_set *open_fds;fd_set close_on_exec_init;fd_set open_fds_init;struct file * fd_array[NR_OPEN_DEFAULT];
};

操作系统全局管理的struct files_struct,整个系统中所有被打开的文件都要被这个结构体管理
每个进程自己打开维护的struct files_struct,分别管理自己打开的文件

在这里插入图片描述

这个指针数组内部的一个个指针就对应着一个个被打开的文件的地址
而文件描述符fd就是这个数组的下标
所以,当用户想要访问一个进程下的文件时,因为每一个进程的PCB是唯一的,所以文件管理数组也唯一的,只要是进程打开了一个文件,就会把文件的*file添加进去
只需要返回这个进程PCB结构体中fd_array数组的下标
就可以找到对应的文件了

下述三个系统调用函数都有一个int fd,当打开一个文件时,
要对这个文件进行写、读、操作,都需要传递open时返回的文件描述符fd
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用fd去找到对应的文件然后执行相关操作
对文件的读写等操作的数据改动都是在缓冲区内进行
然后由操作系统刷新到磁盘对应位置
所以,读取文件,本质上就是从文件的文件内核缓冲区内加载数据到应用层的用户级缓冲区

4.标准输入、输出、错误

0:标注输入 (键盘)
1:标准输出 (显示器)
2:标准错误 (显示器)

int fd1 = open("text1.txt",O_WRONLY | O_CREAT);
int fd2 = open("text2.txt",O_WRONLY | O_CREAT);
int fd3 = open("text3.txt",O_WRONLY | O_CREAT);
int fd4 = open("text4.txt",O_WRONLY | O_CREAT);printf("fd1 = %d\nfd2 = %d\nfd3 = %d\nfd4 = %d\n",fd1,fd2,fd3,fd4);

在这里插入图片描述
确实多出了4个,文件文件描述符从3开始,编号0 1 2的fd去哪里了?
在这里插入图片描述
C语言中,会为我们默认打开三个流stdin标准输入,stdout标准输出,stderr标准错误,0、1、2为编号的fd就已经被占用
C语言中,文件流是以FILE的形式被管理的,毫无疑问FILE是对Linux文件系统的封装,FILE内部一定存储了fd,否则无法通过fd来访问特定的文件,其中FILE的_fileno成员就是fd

#include <stdio.h>int main()
{int fd1 = stdin->_fileno;int fd2 = stdout->_fileno;int fd3 = stderr->_fileno;printf("stdin->_fileno = %d\n", fd1);printf("stdout->_fileno = %d\n", fd2);printf("stderr->_fileno = %d\n", fd3);return 0;
}

在这里插入图片描述
LInux下一切皆文件
在Linux操作系统中的每一个驱动设备都创建了struct file结构体
结构体内部的属性就是设备的属性数据和函数指针
所以,尽管每一个设备的操作方法不一样,但可以把方法的返回值、参数设置成一样的,然后让这些函数指针指向底层的硬件设备的操作方法,站在Linxu的角度来看这些硬件,也视为文件
实现这种组织的技术其实就是多态
所以对于硬件这一层,在Linux下叫做vfs,即vitural file system虚拟软件系统
在这里插入图片描述

5.重定向

5.1什么是重定向

文件描述符的分配规则:查看自己的文件描述表,分配最小的没有被使用的fd
printf和scanf作为C语言的函数接口,同样无法直接和显示器和键盘作交互,其必须依靠相应的文件,也就是标准输出和标准输入
但是依靠的指向并不是FILE*,而是文件描述符,printf依靠1号文件,scanf依靠0号文件

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{close(1);//关掉1号文件(stdout)int fd1 = open("log.txt",O_WRONLY | O_CREAT | O_APPEND,0666);//打开log.txtprintf("Hello Linux\n");//向屏幕打印printf("Hello Linux\n");printf("Hello Linux\n");printf("Hello Linux\n");return 0;
}

可以看到Hello Linux并没有如愿打印在屏幕上,因为printf只往1号文件里写,就算使用fprintf向stdout输出也不会输出到屏幕
说明printf函数和stdout只认文件描述符1,不管1此时还是不是
标准输出
在这里插入图片描述
但1号文件被关闭,系统给新文件log.txt分配最小的没有被使用的fd,也就是1号,所以本来写入到显示器里的内容写入到了log.txt
在这里插入图片描述
这就是重定向,重定向的本质:是在内核中改变文件描述符表特定下标的内容

5.2输入重定向和输出重定向

>代表输出重定向,将输出从显示器更改到指定文件
<代表输入重定向,将输入从键盘更改到指定文件

测试:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{printf("printf->stdout\n");fprintf(stdout,"fprintf->stdout\n");fprintf(stderr,"fprintf->stderr\n");return 0;
}

在这里插入图片描述
直接运行会向显示器打印
在这里插入图片描述
在这里插入图片描述

重定向后标准输出被重定向到文件中了,但是标准错误仍然还是输出到显示器中

因为>是输出重定向,只会更改标准输出stdout的文件描述符,也就是将指向显示器的文件描述符1更改指向log,txt,但是并不会更改标准错误stderr的文件描述符2,所以标准错误依然写入到显示器上,只有标准输出写入到了指定的文件中

>:将命令的标准输出重定向到文件,会覆盖文件内容。
<:将文件内容作为命令的标准输入。
>>:将命令的标准输出重定向到文件,追加到文件末尾,不会覆盖文件内容。

5.3系统调用的重定向dup2

操作系统提供一个专门用于文件描述符改向的系统调用就叫做dup2
在这里插入图片描述

oldfd:原始文件描述符,表示要复制的文件描述符。
newfd:目标文件描述符,表示将 oldfd复制给的newfd
返回值:
成功时dup2 返回 newfd(复制操作后新的文件描述符)
失败时返回 -1,并将 errno 设置为相应的错误代码。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>int main() 
{int fd;// 打开文件,如果文件不存在则创建,权限为0644fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);// 将标准输出重定向到fddup2(fd, STDOUT_FILENO);//STDIN_FILENO和STDOUT_FILENO是C语言标准库中定义的宏,分别用于表示标准输入和标准输出的文件描述符,这两个宏在<unistd.h>头文件中定义,通常被赋值为0和1printf("Hello Linux\n");// 关闭原文件描述符close(fd);return 0;
}

在这里插入图片描述

在这里插入图片描述

6.缓冲区

缓冲区本质上就是一块内存区域

fwrite等C语言的文件IO接口,都在底层封装了系统调用接口write,用户调用的所有C语言文件IO接口,都会先写到缓冲区中,然后等到一定条件,在通过一次系统调用,把之前所有缓冲区的数据写入到操作系统中,这个一次性写入过程叫做刷新缓冲区
操作系统也有自己的缓冲区,但是这个是操作系统自己管理的内核缓冲区,其决定了wirte等系统调用接口写入的数据何时写入到内存中,但不是该博客讨论的范围,后续讨论的缓冲区都是用户级缓冲区(语言级别的文件缓冲区)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>int main()
{close(1);int fd = open("myfile.txt", O_WRONLY|O_CREAT, 0666);printf("fd: %d\n", fd);//fflush(stdout);close(fd);exit(0);//中断程序}

在这里插入图片描述
当运行上述代码时,即使对一个文件写入了内容,也没有显示
使用了fflush函数之后,就显示了
在这里插入图片描述
原因就是struct FILE 结构体内还有一个语言级别的文件缓冲区
我们使用的printf、fprintf函数等写入的数据都是写到了语言级别的文件缓冲区,而不是到了内存的缓冲区
所以fflush函数所作的工作其实就是把语言级别的缓冲区刷新到内存中
所以如果在文件关闭之前,没有进行刷新,那么,就无法把语言级的缓冲区刷新到内存

用户级缓冲区的刷新策略有以下几种:

1.无缓冲:不进行缓冲,直接输出
2.行缓冲:向显示器写入时,'\n’会强制刷新缓冲区,也就是一行一行刷新缓冲区
3.全缓冲:向普通文件写入时,一般缓冲区被写满才会刷新
4.程序结束,强制刷新缓冲区
5.用户调用flush函数,强制刷新缓冲区

缓冲区被struct FILE管理,由于每个文件的FILE是独立的,因此每个文件的缓冲区也是独立的

特殊情况:

#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{fprintf(stdout,"fprintf->stdout\n");char* temp = "write\n";write(1,temp,strlen(temp));fork();return 0;
}

我们成功将内容输出到了显示器
但是,当我们将这些内容重定向到文件中,C语言库的输出打印了两次
在这里插入图片描述
为什么write不打印两次?
当我们重定向时,write是系统调用,直接写入struct file的缓冲区(文件内核的缓冲区)

为什么fprintf在fork之前就已经完成了却打印了两次?
fprintf因为是语言层面的调用,将内容写入FILE结构体的缓冲区(语言级别的文件缓冲区),原本向显示器输出的策略是行刷新,但在重定向到log.txt前还没有行刷新将其打印,所以fprint->stdout就被留在了缓冲区
当子进程被创建时会继承父进程的数据和代码,stdin的FILE指向的缓冲区也会被继承
所以当父子进程同时进行至刷新缓冲区时,分别输出了一句fprint->stdout

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

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

相关文章

鸿蒙HarmonyOS 【ArkTS组件】通用属性-背景设置

&#x1f4d1;往期推文全新看点&#xff08;附带最新鸿蒙全栈学习笔记&#xff09; 嵌入式开发适不适合做鸿蒙南向开发&#xff1f;看完这篇你就了解了~ 鸿蒙岗位需求突增&#xff01;移动端、PC端、IoT到底该怎么选&#xff1f; 分享一场鸿蒙开发面试经验记录&#xff08;三面…

【76. 最小覆盖子串】

Leetcode算法练习 笔记记录 76. 最小覆盖子串 76. 最小覆盖子串 滑动窗口的hard题目&#xff0c;思路先找到第一个覆盖的窗口&#xff0c;不断缩小左边界&#xff0c;找到更小的窗口并记录。 思路很简单&#xff0c;写起来就不是一会事了&#xff0c;看题解看了几个h&#xff0…

Spring事务简单操作

什么是事务&#xff1f; 事务是一组操作的集合&#xff0c;是一个不可分割的操作 事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时 成功, 要么同时失败. 事务的操作 分为三步&#xff1a; 1. 开启事start transaction/ begin …

Rust 学习笔记:关于错误处理的练习题

Rust 学习笔记&#xff1a;关于错误处理的练习题 Rust 学习笔记&#xff1a;关于错误处理的练习题想看到回溯&#xff0c;需要把哪个环境变量设置为 1&#xff1f;以下哪一项不是使用 panic 的好理由&#xff1f;以下哪一项最能描述为什么 File::open 返回的是 Result 而不是 O…

MCP 协议传输机制大变身:抛弃 SSE,投入 Streamable HTTP 的怀抱

在技术的江湖里&#xff0c;变革的浪潮总是一波接着一波。最近&#xff0c;模型上下文协议&#xff08;MCP&#xff09;的传输机制就搞出了大动静&#xff0c;决定和传统的服务器发送事件&#xff08;SSE&#xff09;说拜拜&#xff0c;转身拥抱 Streamable HTTP&#xff0c;这…

138. Copy List with Random Pointer

目录 题目描述 方法一、使用哈希表 方法二、不使用哈希表 题目描述 问题的关键是&#xff0c;random指针指向的是原链表的结点&#xff0c;这个原链表的结点对应哪一个新链表的结点呢&#xff1f;有两种办法。一是用哈希表。另一种是复制原链表的每一个结点&#xff0c;并将…

如何评估开源商城小程序源码的基础防护能力?

在电商行业快速发展的背景下&#xff0c;开源商城已经为更多企业或者开发者的首选方案&#xff0c;不过并不是所有的开源商城源码都能让人放心使用&#xff0c;今天就带大家一起了解下如何评估开源商城小程序源码的基础防护能力&#xff0c;帮助大家更好地筛选安全性高的商城源…

[Vue]跨组件传值

父子组件传值 详情可以看文章 跨组件传值 Vue 的核⼼是单向数据流。所以在父子组件间传值的时候&#xff0c;数据通常是通过属性从⽗组件向⼦组件&#xff0c;⽽⼦组件通过事件将数据传递回⽗组件。多层嵌套场景⼀般使⽤链式传递的⽅式实现provideinject的⽅式适⽤于需要跨层级…

悠易科技智能体矩阵撬动AI全域营销新时代

大数据产业创新服务媒体 ——聚焦数据 改变商业 在数字化浪潮与AI技术的双重驱动下&#xff0c;数据营销正经历前所未有的变革&#xff0c;从传统的全域智能营销&#xff0c;迈向更具颠覆性的AI全域营销时代。 麦肯锡的报告显示&#xff0c;采用AI驱动营销的企业&#xff0c;客…

Xilinx XCAU10P-2FFVB676I 赛灵思 Artix UltraScale+ FPGA

XCAU10P-2FFVB676I 是 AMD Xilinx 推出的 Artix UltraScale™ FPGA 器件&#xff0c;内部集成了约 96,250 逻辑单元&#xff0c;满足中等规模高性能应用的需求。该芯片采用 16 nm FinFET 制程工艺&#xff0c;核心电压典型值约 0.85 V&#xff0c;能够在较低功耗下提供高达 775…

Java SpringBoot 项目中 Redis 存储 Session 具体实现步骤

目录 一、添加依赖二、配置 Redis三、配置 RedisTemplate四、创建控制器演示 Session 使用五、启动应用并测试六、总结 Java 在 Spring Boot 项目中使用 Redis 来存储 Session&#xff0c;能够实现 Session 的共享和高可用&#xff0c;特别适用于分布式系统环境。以下是具体的实…

分布式电源的配电网无功优化

分布式电源(Distributed Generation, DG)的大规模接入配电网,改变了传统单向潮流模式,导致电压波动、功率因数降低、网损增加等问题,无功优化成为保障配电网安全、经济、高效运行的关键技术。 1. 核心目标 电压稳定性:抑制DG并网点(PCC)及敏感节点的电压越限(如超过5%…

JS手写代码篇---手写Promise

4、手写promise Promise 是一个内置对象&#xff0c;用于处理异步操作。Promise 对象表示一个尚未完成但预期将来会完成的操作。 Promise 的基本结构 一个 Promise 对象通常有以下状态&#xff1a; pending&#xff08;进行中&#xff09;&#xff1a;初始状态&#xff0c;…

我喜欢的vscode几个插件和主题

主题 Monokaione Monokai Python 语义高光支持 自定义颜色为 self 将 class , def 颜色更改为红色 为装饰器修复奇怪的颜色 适用于魔法功能的椂光 Python One Dark 这个主题只在python中效果最好。 我为我个人使用做了这个主题,但任何人都可以使用它。 插件 1.Pylance Pylanc…

【深度学习新浪潮】大模型时代,我们还需要学习传统机器学习么?

在大模型时代,AI 工程师仍需掌握传统机器学习知识,这不仅是技术互补的需求,更是应对复杂场景和职业发展的关键。以下从必要性和学习路径两方面展开分析: 一、传统机器学习在大模型时代的必要性 技术互补性 大模型(如GPT、BERT)擅长处理复杂语义和生成任务,但在数据量少…

年度工作计划总结述职报告PPT模版一组分享

工作计划总结述职报告PPT模版&#xff1a;工作计划述职报告PPT模版https://pan.quark.cn/s/fba40a5e87da 第一套PPT模版是医院年度工作计划的封面页&#xff0c;有蓝橙配色、医院标题、年度工作计划的大字、英文副标题、汇报人信息和右上角的医院logo区域&#xff0c;右侧还有医…

软件设计师“排序算法”真题考点分析——求三连

一、考点分值占比与趋势分析 综合知识题分值统计表 年份考题数量总分值分值占比考察重点2018222.67%时间复杂度/稳定性判断2019334.00%算法特性对比分析2020222.67%空间复杂度要求2021111.33%算法稳定性判断2022334.00%综合特性应用2023222.67%时间复杂度计算2024222.67%分治…

华为云Flexus+DeepSeek征文|基于华为云Flexus云服务的云服务器单机部署Dify-LLM应用开发平台

目录 一、前言 二、华为云Flexus云服务优势 三、华为云Flexus一键部署Dify 3.1 选择模板 3.2 参数配置 3.3 资源栈设置 3.4 配置确认 3.5 创建执行计划 3.6 部署 四、Dify-LLM应用开发平台初体验 4.1 访问Dify-LLM应用开发平台 4.2 设置管理员账户 4.3 登录Dify-LLM应用开发平台…

智能指针RAII

引入&#xff1a;智能指针的意义是什么&#xff1f; RAll是一种利用对象生命周期来控制程序资源&#xff08;如内存、文件句柄、网络连接、互斥量等等&#xff09;的简单技术。 在对象构造时获取资源&#xff0c;接着控制对资源的访问使之在对象的生命周期内始终保持有效&#…

nt!MiRemovePageByColor函数分析之脱链和刷新颜色表

第0部分&#xff1a;背景 PFN_NUMBER FASTCALL MiRemoveZeroPage ( IN ULONG Color ) { ASSERT (Color < MmSecondaryColors); Page FreePagesByColor[Color].Flink; if (Page ! MM_EMPTY_LIST) { // // Remove the first entry on the zeroe…