FATFS函数浅谈 看完学会FATSFS,建议收藏

news2024/11/23 12:20:01

目录

一、注册工作区域

二、打开文件夹

三、读取文件夹

四、打开\新建一个文件

五、读取文件

六、写文件 

七、移动文件指针

 八、截断文件

九、刷新缓存消息 

十、新建文件夹

十一、删除文件或文件夹

十二、重命名\移动文件或文件夹

十三、获取文件信息

十四、改变文件属性 

 十五、改变时间戳


刚开始看到 FATFS 时,一头雾水,不知道从何下手,网上也搜了很多资料,要么高深莫测,要么简单地一笔代过.断断续续地摸索了一段时间,算是对文件系统有了初步的认识,整理一下思路,将自己的学习过程,及学习心得写出来与大家分享, 文笔有限,力求简洁易懂,希望对初学者有所帮助,不足之处请指正.
笔者用的是酷学玩 summer V1.3 的开发板,64M 的 microSD 卡(已格式化为 FAT32 格式),底层驱动是 yuanyin 移植的,如果你用的不是酷学玩 stm32 的板子,那也没关系,网上有很多移植的例程,可以参照着尝试移植;或者根据酷学玩的例程修改也可.
本文主要介绍 FATFS 的 API 函数,仅针对初学者入门,高手请拍砖.
例程中用到的全局变量定义如下:

FATFS fs;     // Work area (file system object) for logical drive
FIL fsrc, fdst; // file objects

FRESULT res; // FatFs function common result code

UINT br, bw; // File R/W count

一、注册工作区域

FRESULT f_mount (
BYTE
Drive, /* Logical drive number */
FATFS*
FileSystemObject /* Pointer to the work area */
)

函数说明:
1. 此函数的作用就是在磁盘里注册一个缓冲区域,用来存储 FAT32 文件系统的一些相关信
息.
2. 参数说明:
a) Drive : 盘符
b) *FileSystemObject : 指向缓冲区域的指针
3. 对磁盘进行操作之前,这个函数是不可少的
例程 : f_mount(0 , &fs);

二、打开文件夹

FRESULT f_opendir (
DIR*
DirObject, /* Pointer to the blank directory object
structure */
const TCHAR*
DirName /* Pointer to the directory name */
)

函数说明:
1. 此函数可以打开一个已存在的文件夹
2. 参数说明:
a) *DirObject : 指向一个空白的结构体,用来存储要打开的文件夹信息
b) *DirName : 指向该文件夹名称的指针


三、读取文件夹

FRESULT f_readdir (
DIR*
DirObject, /* Pointer to the open directory object */
FILINFO*
FileInfo /* Pointer to the file information structure */
);

函数说明:
1. 此函数按照顺序读取文件夹内文件
2. 参数说明:
a) *DirObject : 指向读取的文件夹的信息结构体的指针
b) *FileInfo : 指向文件信息结构体,用来存储读取到的文件的信息
3. 重复调用此函数可读取文件夹内所有文件
4. 当所有文件读取结束,函数返回一个空字符串到 f_name[] 中
5. 如果一个空指针赋给 *FileInfo ,将返回从第一个文件开始读取.

例程:这段程序先打开文件夹 folde/move ,然后查找其中的存档文件,并通过串口输出
读取的文件名

if (f_opendir(&dirs, "folder/move") == FR_OK) //打开文件夹
{
while (f_readdir(&dirs, &finfo) == FR_OK) //按照顺序读文件夹
{
if(!finfo.fname[0]) break; //如果文件名为 0,结束
{
if(finfo.fattrib == AM_ARC) //判断文件属性
Debug("文件名:%s\r\n",finfo.fname);
}
}
}

串口输出如下:


在 PC 上查看 SD 卡:


可以看到,程序输出了后面三个文件的名称,对文件夹没作处理,因为在程序里
对文件属性进行了判断:
if(finfo.fattrib == AM_ARC),意思是只对存档文件进行处理;
至于什么是存档文件,以下是在百度知道搜到的结果:
视窗系统中文件属性有四种类型,我来告诉你这四种类型是什么意思:
只读-表示该文件不能被修改
隐藏 -表示该文件在系统中是隐藏的,在默认情况下用户不能看见这些文件。
系统 - 表示该文件是操作系统的一部分。
存档- 表示该文件在上次备份前已经修改过了,一些备份软件在备份系统后会把这些文件默
认的设为存档属性。
存档属性在一般文件管理中意义不大,但是对于频繁的文件批量管理很有帮助。

四、打开\新建一个文件

FRESULT f_open (
FIL*
FileObject, /* Pointer to the blank file object structure
*/
const TCHAR*
FileName, /* Pointer to the file neme */
BYTE
ModeFlags /* Mode flags */
)

 函数说明:
1. 此函数可以打开,或新建一个文件
2. 参数说明
a) *FileObject : 指向一个用来存储文件对象的空结构体的指针
b) *FileName : 指向文件名的指针
c) ModeFlags : 打 开 方 式 , 可 以 是 以 下 一 种 或 几 种 的 组 合 ( 默 认 方 式 是
FA_OPEN_EXISTING)
ValueValueValueValue DescriptionDescriptionDescriptionDescription
FA_READ 读模式,(读写模式可同时生效)
FA_WRITE 写模式,(读写模式可同时生效)
FA_OPEN_EXISTING 默认打开方式
FA_OPEN_ALWAYS 打开文件,如果文件不存在,则创建一个新文件;
用此种方式,可以用 f_lseek 在文件后追加数据
FA_CREATE_NEW 新建文件,如果文件已存在,则新建失败
FA_CREATE_ALWAYS 新建文件,如果文件已存在,覆盖旧文件


五、读取文件


FRESULT f_read (
FIL*
FileObject, /* Pointer to the file object structure */
void*
Buffer, /* Pointer to the buffer to store read data */
UINT
ByteToRead, /* Number of bytes to read */
UINT*
ByteRead /* Pointer to the variable to return number of bytes
read */
);

函数说明:
1. 这个函数可以读取文件的内容
2. 参数说明:
a) *FileObject : 指向文件对象结构体的指针
b) *Buffer : 指向存储读取到的数据的缓冲的指针
c) ByteToRead : 准备读取的字节数
d) *ByteRead :
i. 它的作用就是用来检测文件的末尾,就是下面例程中的这一句:
if (res || br < sizeof(buffer)) break;
ii. 每次 f_read 执行完后,*ByteRead 值等于本次读取到的字节数,若*ByteRead
<ByteToRead,即本次读取到的字节小于准备读取的字节,说明读指针已到达
文件末尾.

例程:以读取的方式打开文件,然后将文件内容通过串口输出。

res = f_open(&fsrc, "news/news.txt", FA_READ);
if(!res)
{
Debug("open news/news.txt : %d\r\n",res);
br=1;
a=0;
Debug("文件内容:");
for (;;)
{
for(a=0; a<512; a++) buffer[a]=0;
res = f_read(&fsrc, buffer, sizeof(buffer), &br);
Debug("%s\r\n",buffer);
if (res || br < sizeof(buffer)) break; // error or eof
}
}
f_close(&fsrc); //

不论是打开,还是新建文件,一定记得关闭运行后串口输出结果:

下面是在PC中查看:

 

六、写文件 

 

FRESULT f_write (
FIL*
FileObject, /* Pointer to the file object structure */
const void*
Buffer, /* Pointer to the data to be written */
UINT
ByteToWrite, /* Number of bytes to write */
UINT*
ByteWritten /* Pointer to the variable to return number of
bytes written */
);

函数说明:
1. 此函数用来向文件中写入数据,前提是以写文件的方式打开文件
2. 参数说明:
a) *FileObject : 指向文件对象结构体的指针
b) *Buffer : 指向数据缓冲的指针
c) ByteToWrite : 准备写入的字节数
d) *ByteWritten : 记录已写入的字节数,用来检测是否写完
3. 后两个参数的长度都是两个字节,计数值最大为 65536,所以一次写入字节数最大为
64K。一般情况下一次不会写这么长的数据,因为就算 RAM 足够用,也不会在里面开一
个几十 K 的数据缓冲区。
例程:
结合前面的 f_open 函数,在下面例程中以写的方式新建一个 txt 文档,然后写入 100 个字节。
已定义:unsighed char buffer[100] = "This is a new file, the data is just written in! 这是一个新
文件,数据也是新的!";

res = f_open(&fsrc, "new/NewText.txt", FA_WRITE | FA_CREATE_ALWAYS);
if (res == FR_OK)
{
Debug("create file ok!\r\n");
Debug("start write!\r\n");
do
{
res = f_write(&fsrc, buffer, 100,&bw);
if(res)
{
Debug("write error : %d\r\n",res);
break;
}
Debug("write ok!\r\n");
}
while (bw < 100); // 判断是否写完(bw > 100,表示写入完成)
}
f_close(&fsrc); // 关闭文件,必须和 f_open 函数成对出现

运行后串口输出:

 下面是PC中查看结果:

 

掌握以上几个函数后,可以利用 FATFS 对SD卡进行基本的读写操
作了。下面介绍另外几个常用的函数。

七、移动文件指针

FRESULT f_lseek (
FIL*
FileObject, /* Pointer to the file object structure */
DWORD
Offset /* File offset in unit of byte */
)

函数说明:
1. 此函数在对已打开的文件进行读或写时,可以移动当前指针位置
2. 参数说明:
a) FileObject : 指向文件对象结构体的指针
b) Offset : 指针移动的长度
例程:

res = f_open (&fsrc ,"news/news.txt", FA_WRITE);
res = f_lseek (&fsrc , 500); 指针指向第 500 个字节
res = f_write (&fsrc , "500" ,3 , &bw);
res = f_lseek (&fsrc , fsrc.fptr + 100); 指针向前移动 100 个字节
res = f_write (&fsrc , "forward" ,8 , &bw);
res = f_lseek (&fsrc , fsrc.fptr - 200); 指针向后移动 200 个字节
res = f_write (&fsrc , "backward" , 9, &bw);
res = f_lseek (&fsrc , fsrc.fsize); 指针指向文件末尾
res = f_write (&fsrc , "end" ,3 , &bw);
res = f_close ( &fsrc );

运行后在PC中查看结果:

 

 八、截断文件

FRESULT f_truncate (
FIL*
FileObject /* Pointer to the file object */
);

函数说明:
1. 此函数可以在将文件在当前指针处截断
2. 参数说明:
a) *FileObject : 指向文件对象结构体的指针
3. 此函数可以截断文件,也可以延长文件长度
例程:以上节 news/news.txt 为基础,本段程序可将文件在指定长度处截断

res = f_open (&fsrc ,"news/news.txt", FA_WRITE);
res = f_lseek (&fsrc , 60); 指针指向第 60 个字节
res = f_truncate (&fsrc ); 将文件在此截断
res = f_sync ( &fsrc ); 关闭文件

 上图为运行程序之前在PC上查看
下图为运行程序之后,,从右面文件夹中可以看出,文件大小变成了 60 个字节.

九、刷新缓存消息 

FRESULT f_sync (
FIL*
FileObject /* Pointer to the file object */
);

函数说明:
1. 此函数功能兼容 f_close,它于 f_close 的区别就是执行后,当前文件是否仍然有效.
2. 参数说明:
a) *FileObject : 指向文件对象结构体的指针
3. 调用此函数后,当前文件仍然可读可写可查询.
4. 当文件处于长时间的写模式,如数据记录时,定期调用此函数,或在写入数据后立即调用
此函数,可以减少因断电等意外情况带来的损失.有点 WORD 中后台定期保存的意思

十、新建文件夹

FRESULT f_mkdir (
const TCHAR*
DirName /* Pointer to the directory name */
);

函数说明:
1. 新建一个文件夹
2. 参数说明:
a) *DirName : 指向将要创建的文件夹名的指针
3. 文件名应符合 fatfs 标准,不能包含非法字符,
4. 若不支持长文件名,文件名长度不能大于 8,否则新建不成功
5. 例程:

a) f_mkdir("new");
b) f_mkdir("folder/new");

十一、删除文件或文件夹

FRESULT f_unlink (
const TCHAR*
FileName /* Pointer to the object name */
);

函数说明:
1. 此函数可以删除一个文件或文件夹
2. 参数说明:
a) *FileName : 指向文件或文件夹的名称的指针
3. 删除文件夹时:
a) 不能为当前文件夹
b) 不能为非空文件夹
4. 删除文件时
a) 不能为已打开文件
b) 不能为只读文件

十二、重命名\移动文件或文件夹

FRESULT f_rename (
const TCHAR*
OldName, /* Pointer to old object name */
const TCHAR*
NewName /* Pointer to new object name */
);

函数说明:
1. 此函数可以移动或重命名一个文件或文件夹
2. 参数说明:
a) *OldName : 指向旧文件名的指针
b) *NewName : 指向新文件名的指针
3. 此函数可重命名 文件 或 文件夹 ,而不论文件夹是否为空
4. 此函数可移动 文件 或 文件夹 ,而不论文件夹是否为空
例程:

res = f_rename("folder/old.txt","folder/newname.txt"); //重命名 文件,
res = f_rename("folder/123.txt","new/456.txt"); //将文件夹 folder 中的 123.txt 文件,移动到文件
夹 new 中并重命名为 456.txt

十三、获取文件信息

FRESULT f_stat (
const TCHAR*
FileName, /* Pointer to the file or directory name */
FILINFO*
FileInfo /* Pointer to the FILINFO structure */
);

函数说明:
1. 此函数可以获取文件的最近修改时间,属性等信息,获取的信息存在 fileinfo 结构体中
2. 参数说明:
a) *FileName: 指向文件名的指针
b) *FileInfo: 指向保存文件信息的结构体的指针
3. 如果目标是文件夹,获取的大小为 0.
4. 此函数对根目录无效
5. 时间和日期均为两个字节,存储格式如下
a) 日期:
i. bit15...bit9: 年 减去 1980
ii. bit8 ... bit5: 月
iii. bit4 ... bit0: 日
b) 时间:
i. bit15... bit11 : 时
ii. bit10... bit5 : 分
iii. bit4 ... bit0 : 秒 除以 2
c) 如
i. 日期:00000010 00100001,表示 1981 年 1 月 1 日
ii. 时间:00001000 00100001,表示 1 点 1 分 2 秒
例:

res = f_stat("folder/newname.txt", &finfo); //读取 folder 目录下 newname.txt 文件的信息
if( res )
Debug("newname.txt err : %d\r\n", res);
else
{
Debug("newname.txt size : %lu\r\n",finfo.fsize);
Debug("fdate : %d\r\n",finfo.fdate);
Debug("ftime : %d\r\n",finfo.ftime);
Debug("fattrib : %d\r\n",finfo.fattrib);
}

串口输出结果:

 结果分析:

 

 以下式电脑侑见属性查看结果:

和串口读出来的结果一样。

十四、改变文件属性 

FRESULT f_chmod (
const TCHAR*
FileName, /* Pointer to the file or directory */
BYTE
Attribute, /* Attribute flags */
BYTE
AttributeMask /* Attribute masks */
);

函数说明:
1. 此函数可以修改文件或文件夹的属性
2. 可修改的属性只能是以下一种或几种的组合,对其它属性无效

3. 参数说明:
  a) *Filename:指向文件或文件夹的名称的指针
  b) Attribute:要置位的属性
  c) AttributeMask:需要改变的属性(包括要置位的和要清除的属性)


4. 使用方法:
a) Attribute 须为 AttributeMask 的子集
b) 函数对 AttributeMask 中的属性集合进行处理,若属性包含在 Attribute
中,则置位,否则清除
例程:
1.对文件 newname.txt,置位 ARC 和 SYS 属性,取消 HID 和 REO 属性

res = f_chmod("folder/newname.txt", AM_ARC | AM_SYS, AM_ARC | AM_RDO | AM_HID |
AM_SYS);
if( res )
Debug("err :%d\r\n", res);
else
{
res = f_stat("folder/newname.txt", &finfo);
Debug("%d\r\n",finfo.fattrib);
}

2.对文件夹 new,置位 SYS 和 ARC 属性,取消 HID 和 RDO 属性

res = f_chmod("new", AM_SYS | AM_ARC, AM_ARC | AM_RDO | AM_HID | AM_SYS);
if( res )
Debug("err :%d\r\n", res);
else
{
res = f_stat("new", &finfo);
Debug("%d\r\n",finfo.fattrib);
}

 十五、改变时间戳

FRESULT f_utime (
const TCHAR*
FileName, /* Pointer to the file or directory path */
const FILINFO*
TimeDate /* Time and data to be set */
);

函数说明:
1. 此函数可以更改文件的最近修改时间
2. 参数说明:
a) Filename :指向文件的指针
b) Timedate :指向文件信息结构体的指针
例:

FRESULT set_timestamp ( char *obj, /* Pointer to the file name */
int year, int month, int mday, int hour, int min, int sec
)//
{
FILINFO fno;
fno.fdate = (WORD)(((year - 1980) * 512U) | month * 32U | mday);
fno.ftime = (WORD)(hour * 2048U | min * 32U | sec / 2U);
return f_utime(obj, &fno);
}
res = set_timestamp("123.txt",2001,06,05,02,03,34);//修改 123.txt 时间
Debug("%d\r\n",res);
‘

执行函数后,串口返回 0
在 PC 上右键属性可以看到结果如下:

先写到这,后面的函数,用到时再研究:

• f_forward - Forward file data to the stream directly
• f_chdir - Change current directory
• f_chdrive - Change current drive
• f_getcwd - Retrieve the current directory
• f_gets - Read a string
• f_putc - Write a character
• f_puts - Write a string
• f_printf - Write a formatted string

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

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

相关文章

KNN算法及Python实现

0 建议学时 2学时 1 KNN算法 1.1 KNN原理 KNN&#xff1a;K Nearest Neighbors&#xff0c;即K个最近的邻居&#xff1b; 预测一个新值xxx&#xff0c;根据距离最近的K个点的类别来判断xxx属于哪一类。 算法核心要点&#xff1a; K值的选取非常重要&#xff1b; 距离公式…

山东大学电磁场与电磁波期末试题

文章目录一、电磁场的基本规律二、静态电磁场及其边值问题的解三、分离变量法四、均匀平面波的反射与透射五、时变电磁场与均匀平面波在无界空间中的传播六、导行电磁波七、电磁辐射往年真题回忆复习建议一、电磁场的基本规律 设在 x<0x<0x<0 处为真空&#xff0c;x&…

LeetCode分类刷题----回溯算法

回溯1.回溯问题77.组合216.组合总和|||17.电话号码的字母组合39.组合总和40.组合总和||131.分割回文串93.复原IP地址78.子集90.子集||491.递增子序列46.全排列47.全排列||51.N皇后37.解数独1.回溯问题 77.组合 思路&#xff1a; 回溯的本质是用一棵树来描述&#xff0c;用pat…

Gitee码云 操作

1&#xff1a;Git团队协作机制1.1&#xff1a;团队内协作1.2&#xff1a;跨团队协作2&#xff1a;Gitee码云 操作码云网址&#xff1a; https://githee.com/2.1&#xff1a;创建远程仓库2.2&#xff1a;远程仓库操作命令名称作用git remote -v查看当前所有远程地址别名git remo…

Java缓存面试题——Redis应用

文章目录1、为什么要使用Redis做缓存&#xff1f;2、为什么Redis单线程模型效率也能那么高&#xff1f;3、Redis6.0为什么要引入多线程呢&#xff1f;4、Redis常见数据结构以及使用场景字符串&#xff08;String&#xff09;哈希(Hash)列表&#xff08;list&#xff09;集合&am…

【机器学习】马尔可夫链与隐马尔可夫模型(HMM)

1.马尔可夫链(Markov Chain) 马尔可夫链&#xff08;Markov chain&#xff09;&#xff0c;又称离散时间马尔可夫链&#xff08;discrete-time Markov chain&#xff09;&#xff0c;因俄国数学家安德烈马尔可夫&#xff08;A.A.Markov&#xff09;得名。描述的是状态空间中经过…

Win11系统user profile service服务登录失败解决方法

Win11系统user profile service服务登录失败解决方法分享。有用户在使用电脑的时候遇到了一些问题&#xff0c;系统的user profile service服务无法登录了。出现这个问题可能是系统文件损坏&#xff0c;或者中了病毒。接下来我们一起来看看如何解决这个问题的操作方法分享吧。 …

【unity细节】基于unity子对象(如相机)为什么无法进行z轴的拖拽移动和z轴自动归位的问题

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐基于unity子对象为什么无法进行z轴的拖拽移动和z轴自动归位⭐ 文章目录⭐基于u…

学习系统编程No.5【虚拟地址空间】

引言: 北京时间&#xff1a;2023/2/22&#xff0c;离补考期末考试还有5天&#xff0c;不慌&#xff0c;刚午觉睡醒&#xff0c;闹钟2点20&#xff0c;拖到2点50&#xff0c;是近以来&#xff0c;唯一一次有一种睡不醒的感觉&#xff0c;但是现在却没有精神&#xff0c;因为听了…

【Spring Cloud Alibaba】007-Nacos 配置*

【Spring Cloud Alibaba】007-Nacos 配置* 文章目录【Spring Cloud Alibaba】007-Nacos 配置*一、概述1、概述2、对比 spring cloud config二、基本使用1、在管理界面新建配置2、启动权限3、 搭建 nacos-config 服务第一步&#xff1a;引入依赖第二步&#xff1a;修改 yaml 配置…

交叉编译 MQTT/Mosquitto

交叉编译 MQTT/Mosquitto 概述 Eclipse Mosquitto 是一个开源&#xff08;EPL/EDL许可&#xff09;消息代理&#xff0c;它实现了 MQTT 协议版本 5.0、3.1.1 和 3.1。Mosquitto 重量轻&#xff0c;适用于从低功耗单板计算机到全服务器的所有设备。 MQTT 协议提供了一种使用发…

【Linux】-- 开发工具(vim、gcc、g++、make/Makefile)

目录 Linux编辑器-vim使用 vim的基本概念 vim的简单配置 vim的基本操作 vim进阶命令集 插入模式 从插入模式切换为命令模式 移动光标 删除文字 复制 替换 撤销上一次操作 更改 跳至指定的行 vim底行模式命令集 列出行号 跳到文件中的某一行 查找字符 保存文…

黑马程序员 Java 项目《瑞吉外卖》

教程链接&#xff1a;https://www.bilibili.com/video/BV13a411q753 Gitee 仓库&#xff1a;https://gitee.com/weixinyang1980/reggie_take_out 运行视频&#xff1a; 瑞吉外卖后台运行视频 瑞吉外卖用户端运行视频 目录开发环境搭建数据库环境搭建Maven 项目搭建后台登录功能…

通过连接另一个数组的子数组得到一个数组

给你一个长度为 n 的二维整数数组 groups &#xff0c;同时给你一个整数数组 nums 。 你是否可以从 nums 中选出 n 个 不相交 的子数组&#xff0c;使得第 i 个子数组与 groups[i] &#xff08;下标从 0 开始&#xff09;完全相同&#xff0c;且如果 i > 0 &#xff0c;那么…

Python四大主题之一【 Web】 编程框架

目前Python的网络编程框架已经多达几十个&#xff0c;逐个学习它们显然不现实。但这些框架在系统架构和运行环境中有很多共通之处&#xff0c;本文带领读者学习基于Python网络框架开发的常用知识,及目前的4种主流Python网络框架&#xff1a;Django、Tornado、Flask、Twisted。 …

论文复现:风电、光伏与抽水蓄能电站互补调度运行(MATLAB-Yalmip全代码)

论文复现:风电、光伏与抽水蓄能电站互补调度运行(MATLAB-Yalmip全代码) 针对风电、光伏与抽水蓄能站互补运行的问题,已有大量通过启发式算法寻优的案例,但工程上更注重实用性和普适性。Yalmip工具箱则是一种基于MATLAB平台的优化软件工具箱,被广泛应用于工程界优化问题和…

JVM知识最强总结

类加载运行全过程1.java.exe调用底层jvm.dll创建java虚拟机&#xff0c;2.创建引导类加载器实例&#xff0c;3.完成实例的创建后需要一个启动器&#xff0c;这个是通过sun.misc.launcher类实现&#xff0c;通过该类的getLaunch()方法启动&#xff0c;4.然后调用该类的getClassL…

梳理数字资产,亚马逊云科技助力致盛咨询带来药物研发新福音

作为医疗保健领域的咨询公司&#xff0c;ZS需要保证服务可靠性、敏捷性和安全性的同时&#xff0c;获得经济效益。亚马逊云科技丰富的云服务产品简化了ZS基础架构的搭建&#xff0c;为ZS节省了大量的人力与资金成本。同时&#xff0c;缩短了ZS扩展基础设施的周转时间&#xff0…

一篇文章读懂Android Framework

本文旨在将Framework的框架描绘出来&#xff0c;希望抛砖引玉&#xff0c;对于读者有一定的帮助。前言写在前面&#xff1a;1、有没有必要学习linux内核&#xff1f;我认为是很有必要的。学习linux内核有助于我们加深对一些概念的理解&#xff0c;比如“进程”、“线程”。推荐…

JVM18运行时参数

4. JVM 运行时参数 4.1. JVM 参数选项 官网地址&#xff1a;https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html 4.1.1. 类型一&#xff1a;标准参数选项 > java -help 用法: java [-options] class [args...](执行类)或 java [-options] -jar …