文件基础IO
理解"文件"
1-1 狭义理解
- 文件在磁盘里
- 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的
- 磁盘是外设(即是输出设备也是输入设备)
- 磁盘上的文件 本质是对文件的所有操作,都是对外设的输入和输出简称IO
1-2 广义理解
- Linux 下⼀切皆文件(键盘、显示器、网卡、磁盘…… 这些都是抽象化的过程)
1-3 文件操作的归类认知
- 对于 0KB 的空文件是占用磁盘空间的,文件创建时间,属性,权限....都是需要存储的
- 文件是文件属性(元数据)和文件内容的集合(文件 = 属性(元数据)+ 内容)
- 所有的文件操作本质是文件内容操作和文件属性操作
1-4 系统角度
访问文件,需要先打开文件!谁打开文件??进程打开文件!对文件的操作,本质是:进程对文件的操作!
- 对文件的操作本质是进程对文件的操作
- 磁盘的管理者是操作系统
- 文件的读写本质不是通过 C 语言 / C++ 的库函数来操作的(这些库函数只是为用户提供方便),而是通过文件相关的系统调用接口来实现的
回顾C文件接口
1 #include<stdio.h>2 #include<string.h>3 int main()4 {5 FILE *fp=fopen("log.txt","w");6 7 if(fp==NULL)8 {9 perror("fopen");10 return 1;11 }12 const char *msg="hello bit";13 int cnt=1;14 while(cnt<=10)15 {16 char buffer[1024];17 snprintf(buffer,sizeof(buffer),"%s%d\n",msg,cnt++); 18 fwrite(buffer,strlen(buffer),1,fp);19 }20 21 fclose(fp);22 23 return 0;24 }

稍作修改,实现简单cat命令:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("argv error!\n");
return 1;
}
FILE *fp = fopen(argv[1], "r");
if(!fp){
printf("fopen error!\n");
return 2;
}
char buf[1024];
while(1){
int s = fread(buf, 1, sizeof(buf), fp);
if(s > 0){
buf[s] = 0;
printf("%s", buf);
}
if(feof(fp)){
break;
}
}
fclose(fp);
return 0;
}

输出信息到显示器三种方法
c++还有cout,其实这些都是封装了最原始的writ
#include <stdio.h>
#include <string.h>
int main()
{
const char *msg = "hello fwrite\n";
fwrite(msg, strlen(msg), 1, stdout);
printf("hello printf\n");
fprintf(stdout, "hello fprintf\n");
return 0;
}
2-5 stdin & stdout & stderr
- C默认会打开三个输⼊输出流,分别是stdin, stdout, stderr
- 仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针
- stdin 标准输入 键盘文件
- stdout 标准输出 显示器文件
- stderr标准错误 显示器文件
#include <stdio.h>
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
2-6 打开文件的方式
r:以只读模式打开文本文件,文件指针位于文件开头。r+:以读写模式打开文件,文件指针位于文件开头。可以读取和写入文件内容。w:若文件存在则将其内容清空(截断为零长度),若文件不存在则创建一个新的文本文件用于写入,文件指针位于文件开头。w+:以读写模式打开文件。若文件不存在则创建,若存在则清空内容,文件指针位于文件开头。a:以追加模式打开文件,若文件不存在则创建。文件指针位于文件末尾,写入的内容会追加到文件现有内容之后。a+:以读写和追加模式打开文件。若文件不存在则创建,读取时文件指针位于文件开头,写入时内容总是追加到文件末尾
r
Open text file for reading.
The stream is positioned at the beginning of the file.
r+
Open for reading and writing.
The stream is positioned at the beginning of the file.
w
Truncate(缩短) file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.
w+
Open for reading and writing.
The file is created if it does not exist, otherwise it is truncated.
The stream is positioned at the beginning of the file.
a
Open for appending (writing at end of file).
The file is created if it does not exist.
The stream is positioned at the end of the file.
a+
Open for reading and appending (writing at end of file).
The file is created if it does not exist. The initial file position
for reading is at the beginning of the file,
but output is always appended to the end of the file.
系统文件I/O
打开文件的方式不仅仅是fopen,ifstream等流式,语言层的方案,其实系统才是打开文件最底层的方案。不过,在学习系统文件IO之前,先要了解下如何给函数传递标志位,该方法在系统文件IO接口中会使用到:
一种传递标志位的方法(位图)
#include<stdio.h>2 3 #define ONE_FLAG (1<<0) //0000 0000 0000...0000 00014 #define TWO_FLAG (1<<1) //0000 0000 0000...0000 00105 #define THREE_FLAG (1<<2) //0000 0000 0000...0000 0100 6 #define FOUR_FLAG (1<<3) //0000 0000 0000...0000 0100 7 8 void Print(int flags)9 {10 if(flags & ONE_FLAG)11 {12 printf("One!\n");13 }14 if(flags & TWO_FLAG)15 {16 printf("Two!\n");17 }18 if(flags & THREE_FLAG)19 {20 printf("Three!\n");21 }22 if(flags & FOUR_FLAG)23 {24 printf("Four!\n");25 }26 }27 int main()28 {29 30 Print(1);31 printf("\n");32 Print(1|2);33 printf("\n"); 34 Print(1|2|4); 35 return 0; 36 }

hello.c写文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
umask(0);
int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
if(fd < 0){
perror("open");
return 1;
}
int count = 5;
const char *msg = "hello bit!\n";
int len = strlen(msg);
while(count--){
write(fd, msg, len);//fd: 后⾯讲, msg:缓冲区⾸地址, len: 本次读取,期望写
⼊多少个字节的数据。 返回值:实际写了多少字节数据
}
close(fd);
return 0;
}
hello.c读文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
const char *msg = "hello bit!\n";
char buf[1024];
while(1){
ssize_t s = read(fd, buf, strlen(msg));//类⽐write
if(s > 0){
printf("%s", buf);
}else{
break;
}
}
close(fd);
return 0;
}
open
- 读 int open(const char *pathname,int flags);
- 写 int open (const char *pathname,int flags,mode_t mode );
pathname: 要打开或创建的⽬标⽂件
flags: 打开⽂件时,可以传⼊多个参数选项,⽤下⾯的⼀个或者多个常量进⾏“或”运算,构成
flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定⼀个且只能指定⼀个
O_CREAT : 若⽂件不存在,则创建它。需要使⽤mode选项,来指明新⽂件的访问
权限
O_APPEND: 追加写
返回值:
成功:新打开的⽂件描述符
失败:-1
open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。
#include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 int main()6 {7 8 int fd=open("log.txt",O_CREAT|O_WRONLY,0666); 9 if(fd<0)10 {11 perror("open");12 return 1;13 }14 15 return 0;16 }

下面,权限设的是666但是这里是664,umask掩码给屏蔽了,open是系统调用,权限掩码的影响是在系统内部,只要设置umsk(0);就能解决,umsk是设置文件创建时的掩码可以屏蔽掉系统内部权限的影响,用户设置说明就是什么。write read close lseek ,类比C文件相关接口。
fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。而open close read write lseek 都属于系统提供的接口,称之为系统调用接口。
read
ssize_t read(int fd,void *buf,size_t count);
从指定文件描述符读取count个缓冲区的大小,返回读取成功的字节大小数,小于零表示失败,等于零都到结尾
回忆一下讲操作系统概念时,画的张图:

系统调用接口和库函数的关系,一目了然。
所以,可以认为, f# 系列的函数,都是对系统调用的封装,方便二次开发。
文件描述符fd
0 & 1 & 2
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错
误2.
• 0,1,2对应的物理设备一般是:键盘,显示器,显示器
所以输入输出还可以采用如下方式:
#include <stdio.h>
#include <sys/types.h>
1
2
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
char buf[1024];
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0){
buf[s] = 0;
write(1, buf, strlen(buf));
write(2, buf, strlen(buf));
}
return 0;
}


而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。对于以上原理结论我们可通过内核源码验证:

文件描述符的分配规则
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

输出发现是 fd: 3
关闭0或者2,在看
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

发现是结果是: fd: 0 或者 fd 2 ,可见,文件描述符的分配规则:在files_struct数组当中,找到
当前没有被使用的最小的⼀个下标,作为新的文件描述符。

进程里面有一个stuct*file能找到文件描述符表, file是一个结构体,里面含有文件的各种属性,fd是指针数组,里面通过下标能访问到各自file,文件被打开时,创建file文件,再把file存入文件描述符表中最小的空的fd里面,fd通过地址文件能找到file能访问文件。


进程在调用read等接口时操作系统拿着fd索引来到文件描述符表找到该fd内的file地址,每一个文件都要有自己的文件缓冲区,操作系统预加载,file找到缓冲区,将缓冲区的内容拷贝给read等接口自己的缓冲内,所以读写的本质就是拷贝!
重定向
那如果关闭1呢?看代码:
#include <stdio.h>2 #include <sys/types.h>3 #include <sys/stat.h>4 #include <fcntl.h>5 #include <stdlib.h>6 int main()7 {8 close(1);9 int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);10 11 printf("fd: %d\n", fd); 12 }
把本来应该写入显示器的内容居然写进了文件里!
为什么不显示?因为把标准输出关了。
为什么又写进了文件里?因为打开了这个文件。

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这
种现象叫做输出重定向。常见的重定向有: > , >> , <
那重定向的本质是什么呢?


文件描述符表包含了fd_array[],数组下标就是对应打开的文件,系统默认打开标准输入(0),标准输出(1),标准错误(2),而我要打开新的文件log.txt之前把标准输出关了,此时文件描述符表下标为1的指向就不在是标准输出,后来我open打开了一个文件log.txt,根据文件描述符分配规则,又因为最小未被使用的下标恰好就是刚才释放的下标为1的文件描述符,1的地址就是log.txt的地址,把1返回给上层用户,printf就是往stdout内打印的,它是封装了标准输出fd=1,上述操作是在操作系统内部实现的,而用户层printf只认文件描述符1,通过文件描述符1找到对应的文件写入内容。
所以,这种在操作系统内部更改内容指向,和用户层没关系,这种叫重定向,是在内核上做的狸猫换太子!
使用 dup2 系统调用
#include <unistd.h>
int dup2(int oldfd, int newfd);

输出重定向
从文件输出显示器
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
close(1);
int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);
if(fd<0)return 1;
dup2(fd,1);
printf("fd: %d\n", fd);
printf("hello bit\n");
printf("hello bit\n");
fprintf(stdout,"hello stdout\n");}

输入重定向
从文件输入进显示器
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
int fd = open("log.txt", O_RDONLY);
if(fd<0)return 1;
dup2(fd,0);
while(1)
{char buffer[64];if(!fgets(buffer,sizeof(buffer),stdin))break;printf("%s",buffer);}}

printf是C库当中的IO函数,一般往 stdout 中输出,但是stdout底层访问文件的时候,找的还是fd:1,但此时,fd:1下标所表示内容,已经变成了myfifile的地址,不再是显示器文件的地址,所以,输出的任何消息都会往文件中写入,进而完成输出重定向。那追加和输入重定向如何完成呢?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include<unistd.h>
#include<string.h>
int main(int argc,char* argv[])
{if(argc!=2)exit(1);
int fd = open(argv[1], O_RDONLY);
if(fd<0)return 1;
dup2(fd,0);
while(1)
{char buffer[64];if(!fgets(buffer,sizeof(buffer),stdin))break;printf("%s",buffer);}}

相关文章:
文件基础IO
理解"文件" 1-1 狭义理解 文件在磁盘里磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的磁盘是外设(即是输出设备也是输入设备)磁盘上的文件 本质是对文件的所有操作,都是对外设的输入和输出简称IO 1-2 广义理…...
05vue3实战-----配置项目代码规范
05vue3实战-----配置项目代码规范 1.集成editorconfig配置2.使用prettier工具2.1安装prettier2.2配置.prettierrc文件:2.3创建.prettierignore忽略文件2.4VSCode需要安装prettier的插件2.5VSCod中的配置2.6测试prettier是否生效 3.使用ESLint检测3.1VSCode需要安装E…...
八大排序算法细讲
目录 排序 概念 运用 常见排序算法 插入排序 直接插入排序 思想: 步骤(排升序): 代码部分: 时间复杂度: 希尔排序 思路 步骤 gap的取法 代码部分: 时间复杂度: 选择排序 直接选…...
网络爬虫学习:借助DeepSeek完善爬虫软件,增加停止任务功能
一、引言 我从24年11月份开始学习网络爬虫应用开发,经过2个来月的努力,终于完成了开发一款网络爬虫软件的学习目标。这几天对本次学习及应用开发进行一下回顾总结。前面已经发布了两篇日志: 网络爬虫学习:应用selenium从搜*狐搜…...
docker安装es及分词器ik
系统是macos,docker是docker-desktop 拉取镜像 docker pull bitnami/elasticsearch 启动docker镜像 docker create -e "discovery.typesingle-node" \ --name elasticsearch1 -p 9200:9200 -p 9300:9300 \ bitnami/elasticsearch:8.17.1 测试是否好…...
【论文阅读】On the Security of “VOSA“
On the Security of Verifiable and Oblivious Secure Aggregation for Privacy-Preserving Federated Learning -- 关于隐私保护联邦中可验证与遗忘的安全聚合的安全性 论文来源摘要Introduction回顾 VOSA 方案对VOSA不可伪造性的攻击对于类型 I 的攻击对于类型 II 的攻击 论文…...
Docker 国内最新可用镜像源20250205
2年没用dockerhub了结果今天发现镜像无法拉取了,找了很多镜像都无效,连阿里云镜像都不行了,最后找到下面可以用的。 Docker镜像仓库备注hub.urlsa.us.kg可用http://hub.haod.eu.org可用http://hub.chxza.eu.org可用http://ccoc.eu.org部分地…...
(2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器
Audio Large Language Models Can Be Descriptive Speech Quality Evaluators 目录 1. 概述 2. 研究背景与动机 3. 方法 3.1 语音质量评估数据集 3.2 ALLD 对齐策略 4. 实验结果分析 4.1 MOS 评分预测(数值评估) 4.2 迁移能力(在不同…...
使用 CSS 实现透明效果
在 CSS 中,实现透明效果有几种方法,具体使用哪种方法取决于具体需求。以下是一些常见的方法: 使用 opacity 属性: opacity 属性可以设置整个元素的透明度,包括其所有的子元素。 .transparent { opacity: 0.5; /* 0 表…...
4G核心网的演变与创新:从传统到虚拟化的跨越
4G核心网 随着移动通信技术的不断发展,4G核心网已经经历了从传统的硬件密集型架构到现代化、虚拟化网络架构的重大转型。这一演变不仅提升了网络的灵活性和可扩展性,也为未来的5G、物联网(LOT)和边缘计算等技术的发展奠定了基础。…...
数据库系统概论的第六版与第五版的区别,附pdf
我用夸克网盘分享了「数据库系统概论第五六版资源」,点击链接即可保存。 链接:https://pan.quark.cn/s/21a278378dee 第6版教材修订的主要内容 为了保持科学性、先进性和实用性,在第5版教材基础上对全书内容进行了修改、更新和充实。 在科…...
uniapp小程序自定义中间凸起样式底部tabbar
我自己写的自定义的tabbar效果图 废话少说咱们直接上代码,一步一步来 第一步: 找到根目录下的 pages.json 文件,在 tabBar 中把 custom 设置为 true,默认值是 false。list 中设置自定义的相关信息, pagePath&#x…...
自己实现的一个缓存数据库(搞着玩) .net Core/6/8/9
自己实现的一个缓存数据库(搞着玩) 想法来源特点说明 上代码主体基类测试类 注 想法来源 做过一个小型项目,客户要求易移植,不能使用收费的数据库,最好是一个包搞定,尝试过用sqlite,在部分linux…...
在Qt中,slots 关键字有什么用?
有下面的Qt代码: #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr…...
如何查看linux机器有几个cpu
在 Linux 机器上,你可以使用以下几种方法来查看 CPU 的数量(物理 CPU 和逻辑 CPU): 方法 1:使用 lscpu 命令 lscpu输出示例: CPU(s): 8 Thread(s) per core: 2 Core(s) per socket: 4 Soc…...
Swoole如何处理内存泄漏
Swoole处理内存泄漏的方式主要包括以下几个方面: 一、内存管理机制 Swoole的内存管理机制与普通PHP-CLI程序一致,但它在事件回调函数返回后会自动回收所有局部对象和变量,不需要手动unset。如果变量是一个资源类型,那么对应的资…...
Llama最新开源大模型Llama3.1
Meta公司于2024年7月23日发布了最新的开源大模型Llama 3.1,这是其在大语言模型领域的重要进展。以下是关于Llama 3.1的详细介绍: 参数规模与训练数据 Llama 3.1拥有4050亿(405B)参数,是目前开源领域中参数规模最大的…...
Pixflow - CL-DJI Drone LUTs 120个大疆Drone无人机相机航拍电影级镜头LUT调色预设
120组电影质感DJI大疆无人机航拍视频LOG&Rec 709还原颜色分级调色LUTs预设包Pixflow – CL-DJI Drone LUTs 使用基于城市外观和 DJI 无人机镜头的最佳 Drone Luts 颜色预设来提升您的视频。 120 个出色的颜色分级 LUTS,您可以将其与任何无人机视频素材一起使用…...
了解AI绘图,Stable Diffusion的使用
AI绘图对GPU算力要求较高。 个人电脑配置可参考: CPU:14600kf 盒装 显卡:RTX 4080金属大师 OC,16G显存 主板:z790吹雪d4 内存:芝奇皇家戟4000c18,162G 硬盘:宏基gm7000 1T 散热:追风…...
idea整合deepseek实现AI辅助编程
1.File->Settings 2.安装插件codegpt 3.注册deepseek开发者账号,DeepSeek开放平台 4.按下图指示创建API KEY 5.回到idea配置api信息,File->Settings->Tools->CodeGPT->Providers->Custom OpenAI API key填写deepseek的api key Chat…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
