SOC-ESP32S3部分:23-文件系统

article/2025/8/12 6:47:27

飞书文档https://x509p6c8to.feishu.cn/wiki/SXf5w6seIijVVskvic5cNT2wng4

目前,ESP-IDF 框架支持三种文件系统。

SPIFFS(SPI Flash File System)

  • 简介:SPIFFS 是专门为 SPI NOR Flash 设备设计的轻量级文件系统,适用于资源受限的嵌入式系统,在 ESP32 开发中较为常用。
  • 特点
  • 轻量级:占用资源少,对内存和处理能力的要求较低,适合在资源有限的 ESP32 设备上运行。
  • 磨损均衡:支持基本的磨损均衡功能,能够均匀地将数据写入 Flash 芯片的各个块,延长 Flash 的使用寿命。
  • 简单易用:API 相对简单,易于集成到项目中,开发人员可以方便地进行文件的读写操作。
  • 不支持大文件:由于其设计初衷是用于存储小文件,对于大文件的处理能力有限,且文件系统的最大容量也受到一定限制。
  • 适用场景:适合存储配置文件、小图片、脚本等小文件,例如存储设备的配置信息、简单的网页文件等。

FATFS

  • 简介:FATFS 是一个通用的 FAT 文件系统模块,遵循 ANSI C 标准,与平台无关。ESP-IDF 可以通过移植 FATFS 来支持 FAT12、FAT16 和 FAT32 文件系统。
  • 特点
  • 兼容性好:FAT 文件系统是一种广泛使用的文件系统格式,在各种操作系统(如 Windows、Linux 等)中都能很好地支持,方便与其他设备进行数据交互。
  • 支持大文件:能够处理较大的文件和文件夹,适用于需要存储大文件的场景。
  • 功能丰富:支持文件的创建、删除、读写、重命名等常见操作,还支持文件权限和目录结构。
  • 资源占用较多:相比于 SPIFFS,FATFS 需要更多的内存和处理能力来运行,对系统资源有一定的要求。
  • 适用场景:适合需要与其他设备共享数据、存储大文件的场景,例如存储多媒体文件(如音频、视频)、大型配置文件等。

LittleFS

  • 简介:LittleFS 是一种专为嵌入式系统设计的日志结构文件系统,旨在提供高性能、可靠性和低资源占用。
  • 特点
  • 高性能:采用日志结构设计,具有较高的写入性能和随机访问性能,能够快速地进行文件的读写操作。
  • 可靠性强:支持数据的原子写入和崩溃恢复功能,在系统异常断电或崩溃的情况下,能够保证数据的完整性和一致性。
  • 磨损均衡:提供了更高级的磨损均衡算法,能够更有效地延长 Flash 芯片的使用寿命。
  • 资源占用适中:相比于 FATFS,LittleFS 的资源占用相对较少,但比 SPIFFS 略高。
  • 适用场景:适合对文件系统性能和可靠性要求较高的场景,例如存储实时数据、重要的配置文件等。

课程主要讲解SPIFFS,其它文件系统的使用都是类似的,很容易扩展。

SPIFFS 是一个用于 SPI NOR flash 设备的嵌入式文件系统,支持磨损均衡、文件系统一致性检查等功能。

SPIFFS NVS 的区别

SPIFFS(Serial Peripheral Interface Flash File System)和 NVS(Non-Volatile Storage)都是 ESP32-S3 的存储系统,但它们有一些关键的区别。

NVS 在 SPI NOR flash 上实现了一个有容错性,和磨损均衡功能的键值对存储。

NVS 可以存储一些 PHY 初始化数据,也可以存储其他数据,一些断电存储的数据建议放在这里。

总的来说,SPIFFS 更适合用于存储文件,而 NVS 更适合用于存储键值对数据。具体使用哪种存储系统,取决于应用需求。

1.1、创建分区表

同理,因为文件系统需要用到Flash存储,所以也得进行分区表的创建

# Name,   Type, SubType, Offset,  Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs,      data, nvs,     ,        0x6000,
phy_init, data, phy,     ,        0x1000,
factory,  app,  factory, ,        1M,
storage,  data, spiffs,  ,        0xF0000,

然后通过idf.py menuconfig配置自定义分区表

2.1、注册&格式化文件系统

有了分区后,就可以进行文件系统的注册函数esp_vfs_spiffs_register

esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t *conf);
参数
const esp_vfs_spiffs_conf_t *conf:
指向 esp_vfs_spiffs_conf_t 结构体的指针,包含 SPIFFS 文件系统的配置信息。返回值
esp_err_t
表示函数执行的结果,通常为以下几种情况:
ESP_OK: 成功初始化并挂载 SPIFFS 文件系统。
ESP_FAIL: 挂载或格式化失败。
ESP_ERR_NOT_FOUND: 未找到 SPIFFS 分区。
ESP_ERR_NO_MEM: 内存不足,无法初始化文件系统。
ESP_ERR_INVALID_ARG: 输入参数无效。
其他可能的错误代码,具体取决于底层实现。

esp_vfs_spiffs_conf_t 结构体用于配置 SPIFFS(SPI Flash File System)文件系统的参数。通过设置这些参数,可以控制 SPIFFS 文件系统的挂载行为、分区选择、最大同时打开的文件数以及挂载失败时的处理方式。

字段说明
base_path: 文件系统的挂载路径前缀。所有通过该文件系统访问的文件路径都将基于此路径。。
例如,如果 base_path 设置为 "/spiffs",则文件 hello.txt 的完整路径将是 "/spiffs/hello.txt"。partition_label: 可选参数,指定要使用的 SPIFFS 分区的标签,如果有多个 SPIFFS 分区,可以通过设置 partition_label 来指定具体的分区。
如果不设置,则默认使用第一个子类型为 spiffs 的分区。max_files: 最大同时打开的文件数。format_if_mount_failed: 如果为 true,则在挂载失败时自动格式化文件系统。
说明: 如果挂载 SPIFFS 分区失败(例如分区损坏或未初始化),
设置此标志为 true 可以自动格式化分区,使其重新可用。

使用参考:

    // 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}

3.1、获取文件系统的信息

注册完成后,就可以使用esp_spiffs_info 函数用于获取指定 SPIFFS 分区的总大小和已使用的空间大小。

esp_err_t esp_spiffs_info(const char* partition_label, size_t* total, size_t* used);
参数
const char* partition_label:
SPIFFS 分区的标签。如果设置为 NULL,则使用默认的 SPIFFS 分区。size_t* total:
用于存储 SPIFFS 分区的总大小(以字节为单位)。size_t* used:
用于存储 SPIFFS 分区已使用的空间大小(以字节为单位)。

使用参考:

    // 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}

4.1、检查文件系统的完整性

最后,调用esp_spiffs_check 函数用于检查 SPIFFS 文件系统的完整性。具体来说:

  • 它会扫描指定的 SPIFFS 分区,查找并修复文件系统中的潜在问题。
  • 这个函数可以帮助检测和修复由于突然断电、程序异常终止等原因导致的文件系统损坏。
  • 检查过程包括验证文件系统结构、索引节点、数据块等的正确性。
使用参考// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}

5.1、创建文件、读写操作

如果到这里都没问题,我们就可以用c的文件操作函数进行文件的创建、写入、读取等操作了,最终代码如下:

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"static const char *TAG = "example";void app_main(void)
{// 初始化 SPIFFSESP_LOGI(TAG, "Initializing SPIFFS");// 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}// 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}// 使用 POSIX 和 C 标准库函数来处理文件// 首先创建一个文件ESP_LOGI(TAG, "Opening file"); // 打开文件FILE* f = fopen("/spiffs/hello.txt", "w");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for writing"); // 打开文件失败return;}fprintf(f, "Hello World!\n"); // 写入文件fclose(f);ESP_LOGI(TAG, "File written"); // 文件写入成功// 打开文件进行读取ESP_LOGI(TAG, "Reading file"); // 读取文件f = fopen("/spiffs/hello.txt", "r");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for reading"); // 打开文件失败return;}char line[64];fgets(line, sizeof(line), f); // 读取文件内容fclose(f);// 去掉换行符char* pos = strchr(line, '\n');if (pos) {*pos = '\0';}ESP_LOGI(TAG, "Read from file: '%s'", line); // 读取到的内容// 完成所有操作,卸载分区并禁用 SPIFFSesp_vfs_spiffs_unregister(conf.partition_label);ESP_LOGI(TAG, "SPIFFS unmounted"); // SPIFFS 卸载成功
}

首次启动时,因为需要初始化挂载格式化文件系统,所以会阻塞10s左右,这是正常的

扩展:如何把本地文件烧录到板卡文件系统中?

spiffs_create_partition_image 是一个用于将文件系统中的文件打包成 SPIFFS 镜像并烧录到 ESP32 Flash中的命令,可以在程序烧录阶段一同将自定义的SPIFFS 文件镜像烧录到开发板。

使用方法很简单,例如,我在电脑创建一个txt文件夹,文件夹内部创建一个文件hello1.txt

demo/txt/hello1.txt

this is hello1 txt

然后在demo/main/CMakeLists.txt中,就可以添加spiffs_create_partition_image指令

指令参数如下

spiffs_create_partition_image(分区名 "path/to/files" FLASH_IN_PROJECT)

所以内容如下:

spiffs_create_partition_image(storage "../txt" FLASH_IN_PROJECT)

这句指令的意思是将工程下../txt 目录中的文件打包成 SPIFFS 镜像,并且。

最终用代码打开

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"static const char *TAG = "example";void app_main(void)
{// 初始化 SPIFFSESP_LOGI(TAG, "Initializing SPIFFS");// 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}// 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}// 打开文件进行读取ESP_LOGI(TAG, "Reading file"); // 读取文件FILE* f = fopen("/spiffs/hello1.txt", "r");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for reading"); // 打开文件失败return;}char line[64];fgets(line, sizeof(line), f); // 读取文件内容fclose(f);// 去掉换行符char* pos = strchr(line, '\n');if (pos) {*pos = '\0';}ESP_LOGI(TAG, "Read from file: '%s'", line); // 读取到的内容// 完成所有操作,卸载分区并禁用 SPIFFSesp_vfs_spiffs_unregister(conf.partition_label);ESP_LOGI(TAG, "SPIFFS unmounted"); // SPIFFS 卸载成功
}

http://www.hkcw.cn/article/NOofWBkhnK.shtml

相关文章

[Godot] 如何导出安卓 APK 并在手机上调试

在之前的文章中&#xff0c;我们已经详细介绍了如何配置 Godot 的安卓应用开发环境&#xff0c;包括安装 Android SDK、配置 Java 环境、设置 Godot 的 Android 导出模板等。本篇文章将进一步讲解如何将 Godot 项目导出为安卓 APK 文件&#xff0c;并实现在手机上进行调试运行。…

通用人工智能 (AGI): 定义、挑战与未来展望

摘要 通用人工智能 (AGI) 代表人工智能领域的理想追求&#xff0c;其目标是创造具备人类般广泛智能能力的系统。本文深入探讨 AGI 的核心概念&#xff0c;详细梳理通向 AGI 的潜在技术路径&#xff0c;同时分析实现过程中面临的挑战与应对策略&#xff0c;并对 AGI 的未来发展进…

【CF】Day72——Codeforces Round 890 (Div. 2) CDE1 (二分答案 | 交互 + 分治 | ⭐树上背包)

C. To Become Max 题目&#xff1a; 思路&#xff1a; 二分挺好想的&#xff0c;但是check有点不好写 看到最大值&#xff0c;试试二分&#xff0c;如果 x 可以&#xff0c;那么 x - 1 肯定也可以&#xff0c;所以具有单调性&#xff0c;考虑二分 如何check呢&#xff1f;由于…

Java进阶---JVM

JVM概述 JVM作用&#xff1a; 负责将字节码翻译为机器码&#xff0c;管理运行时内存 JVM整体组成部分&#xff1a; 类加载系统(ClasLoader)&#xff1a;负责将硬盘上的字节码文件加载到内存中 运行时数据区(RuntimeData Area)&#xff1a;负责存储运行时各种数据 执行引擎(Ex…

Linux《文件系统》

在之前的系统IO当中已经了解了“内存”级别的文件操作&#xff0c;了解了文件描述符、重定向、缓冲区等概念&#xff0c;在了解了这些的知识之后还封装出了我们自己的libc库。接下来在本篇当中将会将视角从内存转向磁盘&#xff0c;研究文件在内存当中是如何进行存储的&#xf…

SRD-12VDC-SL-C 继电器‌接线图解

这个继电器可以使用12伏的直流电源控制250伏和125伏的交流电&#xff0c;也可以控制30伏和28伏的直流电&#xff0c;电流都为10安。 此继电器有5个引脚&#xff0c;各个的作用如下&#xff1a; 引脚4和引脚5为触点&#xff0c; 引脚1和引脚3为线圈引脚&#xff0c;接12伏的直…

Linux下目录递归拷贝的单进程实现

1.实验目的 掌握Linux应用程序命令行参数传递方法掌握POSIX API中文件I/O操作方法&#xff0c;包括&#xff1a;打开文件、关闭文件、创建文件、读写文件、确定和改变文件当前位置 2.实验内容 利用POSIX API在Linux系统上编写应用程序&#xff0c;仿写cp命令的部分功能&#…

哈希:闭散列的开放定址法

我还是曾经的那个少年 1.概念 通过其要存储的值与存储的位置建立映射关系。 如&#xff1a;基数排序也是运用了哈希开放定址法的的思想。 弊端&#xff1a;仅适用于数据集中的情况 2.开放定址法 问题&#xff1a;按照上述哈希的方式&#xff0c;向集合插入数据为44&#xff…

数据库基础

MySQL基础 一、什么是数据库 mysql是数据库服务的客户端 mysql是数据库服务的服务器端 本质&#xff1a;基于C&#xff08;mysql&#xff09;S&#xff08;mysqld&#xff09;模式的一种服务网络&#xff0c;一套给我们提供数据存取的服务的网络程序 数据库&#xff1a;一…

多线程——线程池

课程&#xff1a; 什么是线程池 可以自己实现这个功能&#xff0c;自己写一个线程池 jdk也给提供了线程池 为什么要有线程池 Executor框架 任务&#xff1a;就是代码 执行&#xff1a;谁去执行这个代码&#xff0c;之前是Thread执行的&#xff0c; thread: Executor: …

2006-2021年 中国社会状况综合调查CSS数据(含Excel、Stata格式)

2006-2021年 中国社会状况综合调查CSS数据&#xff08;含Excel、Stata格式&#xff09;.ziphttps://download.csdn.net/download/2401_84585615/89784651 https://download.csdn.net/download/2401_84585615/89784651 2006至2021年&#xff0c;中国社会状况综合调查&#xff08…

ReLU的变体

在深度学习中&#xff0c;ReLU&#xff08;Rectified Linear Unit&#xff09;是最常用的激活函数之一&#xff0c;但其存在一些局限性&#xff08;如死亡ReLU问题&#xff09;。为解决这些问题&#xff0c;研究者们提出了多种变体。以下是常见的ReLU变体及其核心特点&#xff…

麦克风和电脑内播放声音实时识别转文字软件FunASR整合包V5下载

我基于FunASR制作的实时语音识别转文字软件当前更新到V5版本。软件可以实时识别麦克风声音和电脑内播放声音转为文字。 FunASR软件介绍 FunASR 是一款基础语音识别工具包和开源 SOTA 预训练模型&#xff0c;支持语音识别、语音活动检测、文本后处理等。 我使用FunASR制作了一…

Ollama 开放 局域网访问 外网访问 mac

目录 问题描述 搜索尝试 最终方案 问题描述 我们在本地安装Ollama模型后通过127.0.0.1:11434访问正常返回 但是无法通过局域网IP访问如&#xff1a; http://192.168.1.158:11434 搜索尝试 搜索发现需要添加环境变量 OLLAMA_HOST 才能开放外网访问 export OLLAMA_HOST0.0.…

让Windows“怀上”macOS,不要太漂亮

记得Windows 11刚发布时&#xff0c;很多人都说它“果味十足”&#xff0c;仿佛是在向macOS靠拢。虽然大家觉得Windows有点“没骨气”&#xff0c;但不得不承认&#xff0c;它的界面确实很美观。 今天给大家介绍两款软件&#xff0c;能让Windows拥有macOS的风格&#xff0c;看起…

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)

文章目录 Gradle配置指南&#xff1a;深入解析settings.gradle.kts&#xff08;Kotlin DSL版&#xff09;settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理&#xff08;Plugin Management&#xff09;基础配置模板案例&#xff1a;Android项目标准配…

Android SDK安装与配置(小白教程)

目录 1、下载&#xff1a; 2、安装&#xff1a; 3、配置环境变量&#xff1a; 4、验证是否安装成功&#xff1a; Android SDK&#xff08;软件开发工具包&#xff09;是一套为开发者提供的全面工具和资源集合&#xff0c;涵盖不同版本平台、各类开发与调试工具、支持库等&a…

[wsl2]MacOS/Win局域网ssh连接wsl2:Ubuntu24.04 LTS

【wsl2】MacOS/Win局域网ssh连接wsl2&#xff1a;Ubuntu24.04 LTS 保证使用的是微软应用商店中下载的Ubuntu发行版本&#xff0c;本文在配置时发现若使用docker所基于的ubuntu系统配置会失败。遂采用默认的子发行版本。写在前面why wsl2&#xff1f;win11的好处 开始配置之前1.…

JAVA游戏打手俱乐部护航小程序+APP+公众号+h5 源码游戏陪玩小程序系统

一、系统概述 JAVA 游戏打手俱乐部护航陪玩系统是一款集小程序、APP、公众号和 H5 于一体的综合性游戏陪玩平台。该系统凭借丰富多样的功能&#xff0c;为游戏玩家和陪玩师傅搭建了便捷的沟通桥梁。其主要功能包括精准分类、优惠券管理、我的团队、师傅申请入驻、师傅端抢单机…

使用Mac下载MySQL修改密码第一篇_数据库

Mac下载MySQL MySQL官网链接MySQL​​​​​​ 当进入到官网后下滑到community社区&#xff0c;进行下载 然后选择community sever下载 这里就是要下载的界面&#xff0c;如果需要下载之前版本的话可以点击archives&#xff0c; 可能会因为这是外网原因&#xff0c;有时候下…