简介

  非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据。

底层存储

  NVS 通过调用 spi_flash_{read|write|erase} API 对主 flash 的部分空间进行读、写、擦除操作,包括 data 类型和 nvs 子类型的所有分区。应用程序可调用 nvs_open API 选择使用带有 nvs 标签的分区,也可以通过调用 nvs_open_from_part API 选择使用指定名称的任意分区。

键值对

  NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持最大键长为 15 个字符,值可以为以下几种类型:

    ◍ 整数型:uint8_tint8_tuint16_tint16_tuint32_tint32_tuint64_t 和 int64_t

    ◍ 以 \0 结尾的字符串;

    ◍ 可变长度的二进制数据 (BLOB)

      *注:字符串值当前上限为 4000 字节,其中包括空终止符。BLOB 值上限为 508,000 字节或分区大小减去 4000 字节的 97.6%,以较低值为准。

  键必须唯一。为现有的键写入新的值可能产生如下结果:

    ◍ 如果新旧值数据类型相同,则更新值;

    ◍ 如果新旧值数据类型不同,则返回错误。

  读取值时也会执行数据类型检查。如果读取操作的数据类型与该值的数据类型不匹配,则返回错误。

NVS 优势

  1、接口更加安全: NVS 不直接操作 address. 对于终端用户而已, 更加安全。

  2、接口使用接近用户习惯,NVS 接口类似于电脑上操作文件一样:
    打开文件(nvs_open), 写文件(nvs_set_xxx), 保存文件(nvs_commit), 关闭文件(nvs_close)
    打开文件(nvs_open), 读取文件(nvs_get_xxx), 关闭文件(nvs_close)

  3、擦写均衡, 使 flash 寿命更长,NVS 在操作少量数据上, NVS 分区更大时, 擦写均衡表现的更为明显。

API 分析参考

初始化

/*** @brief Initialize the default NVS partition.** This API initialises the default NVS partition. The default NVS partition* is the one that is labeled "nvs" in the partition table.** @return*      - ESP_OK if storage was successfully initialized.*      - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages*        (which may happen if NVS partition was truncated)*      - ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table*      - one of the error codes from the underlying flash storage driver*/
esp_err_t nvs_flash_init(void);
/*** @brief Initialize NVS flash storage for the specified partition.** @param[in]  partition_label   Label of the partition. Note that internally a reference to*                               passed value is kept and it should be accessible for future operations** @return*      - ESP_OK if storage was successfully initialized.*      - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages*        (which may happen if NVS partition was truncated)*      - ESP_ERR_NOT_FOUND if specified partition is not found in the partition table*      - one of the error codes from the underlying flash storage driver*/
esp_err_t nvs_flash_init_partition(const char *partition_label);

擦除

/*** @brief Erase the default NVS partition** This function erases all contents of the default NVS partition (one with label "nvs")** @return*      - ESP_OK on success*      - ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the*        partition table*/
esp_err_t nvs_flash_erase(void);
/*** @brief Erase specified NVS partition** This function erases all contents of specified NVS partition** @param[in]  part_name    Name (label) of the partition to be erased** @return*      - ESP_OK on success*      - ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name*        in the partition table*/
esp_err_t nvs_flash_erase_partition(const char *part_name);

打开文件

/*** @brief      Open non-volatile storage with a given namespace from the default NVS partition** Multiple internal ESP-IDF and third party application modules can store* their key-value pairs in the NVS module. In order to reduce possible* conflicts on key names, each module can use its own namespace.* The default NVS partition is the one that is labelled "nvs" in the partition* table.** @param[in]  name        Namespace name. Maximal length is determined by the*                         underlying implementation, but is guaranteed to be*                         at least 15 characters. Shouldn't be empty.* @param[in]  open_mode   NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will*                         open a handle for reading only. All write requests will*              be rejected for this handle.* @param[out] out_handle  If successful (return code is zero), handle will be*                         returned in this argument.** @return*             - ESP_OK if storage handle was opened successfully*             - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized*             - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found*             - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and*               mode is NVS_READONLY*             - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints*             - other error codes from the underlying storage driver*/
esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);
/*** @brief      Open non-volatile storage with a given namespace from specified partition** The behaviour is same as nvs_open() API. However this API can operate on a specified NVS* partition instead of default NVS partition. Note that the specified partition must be registered* with NVS using nvs_flash_init_partition() API.** @param[in]  part_name   Label (name) of the partition of interest for object read/write/erase* @param[in]  name        Namespace name. Maximal length is determined by the*                         underlying implementation, but is guaranteed to be*                         at least 15 characters. Shouldn't be empty.* @param[in]  open_mode   NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will *                         open a handle for reading only. All write requests will *              be rejected for this handle.* @param[out] out_handle  If successful (return code is zero), handle will be*                         returned in this argument.** @return*             - ESP_OK if storage handle was opened successfully*             - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized*             - ESP_ERR_NVS_PART_NOT_FOUND if the partition with specified name is not found*             - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and*               mode is NVS_READONLY*             - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints*             - other error codes from the underlying storage driver*/
esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);

数据写入

/**@{*/
/*** @brief      set value for given key** This family of functions set value for the key, given its name. Note that* actual storage will not be updated until nvs_commit function is called.** @param[in]  handle  Handle obtained from nvs_open function.*                     Handles that were opened read only cannot be used.* @param[in]  key     Key name. Maximal length is determined by the underlying*                     implementation, but is guaranteed to be at least*                     15 characters. Shouldn't be empty.* @param[in]  value   The value to set.*                     For strings, the maximum length (including null character) is*                     4000 bytes.** @return*             - ESP_OK if value was set successfully*             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL*             - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only*             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints*             - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the*               underlying storage to save the value*             - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash*               write operation has failed. The value was written however, and*               update will be finished after re-initialization of nvs, provided that*               flash operation doesn't fail again.*             - ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long*/
esp_err_t nvs_set_i8  (nvs_handle handle, const char* key, int8_t value);
esp_err_t nvs_set_u8  (nvs_handle handle, const char* key, uint8_t value);
esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value);
esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value);
esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value);
esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value);
esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value);
esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value);
esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value);
/**@}*/ /*** @brief       set variable length binary value for given key** This family of functions set value for the key, given its name. Note that* actual storage will not be updated until nvs_commit function is called.** @param[in]  handle  Handle obtained from nvs_open function.*                     Handles that were opened read only cannot be used.* @param[in]  key     Key name. Maximal length is 15 characters. Shouldn't be empty.* @param[in]  value   The value to set.* @param[in]  length  length of binary value to set, in bytes; Maximum length is*                     508000 bytes or (97.6% of the partition size - 4000) bytes*                     whichever is lower.** @return*             - ESP_OK if value was set successfully*             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL*             - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only*             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints*             - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the*               underlying storage to save the value*             - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash*               write operation has failed. The value was written however, and*               update will be finished after re-initialization of nvs, provided that*               flash operation doesn't fail again.*             - ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long*/
esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length);

数据读出

/**@{*/
/*** @brief      get value for given key** These functions retrieve value for the key, given its name. If key does not* exist, or the requested variable type doesn't match the type which was used* when setting a value, an error is returned.** In case of any error, out_value is not modified.** All functions expect out_value to be a pointer to an already allocated variable* of the given type.** \code{c}* // Example of using nvs_get_i32:* int32_t max_buffer_size = 4096; // default value* esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);* assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);* // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still* // have its default value.** \endcode** @param[in]     handle     Handle obtained from nvs_open function.* @param[in]     key        Key name. Maximal length is determined by the underlying*                           implementation, but is guaranteed to be at least*                           15 characters. Shouldn't be empty.* @param         out_value  Pointer to the output value.*                           May be NULL for nvs_get_str and nvs_get_blob, in this*                           case required length will be returned in length argument.** @return*             - ESP_OK if the value was retrieved successfully*             - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist*             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL*             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints*             - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data*/
esp_err_t nvs_get_i8  (nvs_handle handle, const char* key, int8_t* out_value);
esp_err_t nvs_get_u8  (nvs_handle handle, const char* key, uint8_t* out_value);
esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value);
esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value);
esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value);
esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value);
esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value);
esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value);
/**@}*/ /*** @brief      get value for given key** These functions retrieve value for the key, given its name. If key does not* exist, or the requested variable type doesn't match the type which was used* when setting a value, an error is returned.** In case of any error, out_value is not modified.** All functions expect out_value to be a pointer to an already allocated variable* of the given type.* * nvs_get_str and nvs_get_blob functions support WinAPI-style length queries.* To get the size necessary to store the value, call nvs_get_str or nvs_get_blob* with zero out_value and non-zero pointer to length. Variable pointed to* by length argument will be set to the required length. For nvs_get_str,* this length includes the zero terminator. When calling nvs_get_str and* nvs_get_blob with non-zero out_value, length has to be non-zero and has to* point to the length available in out_value.* It is suggested that nvs_get/set_str is used for zero-terminated C strings, and* nvs_get/set_blob used for arbitrary data structures.** \code{c}* // Example (without error checking) of using nvs_get_str to get a string into dynamic array:* size_t required_size;* nvs_get_str(my_handle, "server_name", NULL, &required_size);* char* server_name = malloc(required_size);* nvs_get_str(my_handle, "server_name", server_name, &required_size);** // Example (without error checking) of using nvs_get_blob to get a binary data* into a static array:* uint8_t mac_addr[6];* size_t size = sizeof(mac_addr);* nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size);* \endcode** @param[in]     handle     Handle obtained from nvs_open function.* @param[in]     key        Key name. Maximal length is determined by the underlying*                           implementation, but is guaranteed to be at least*                           15 characters. Shouldn't be empty.* @param         out_value  Pointer to the output value.*                           May be NULL for nvs_get_str and nvs_get_blob, in this*                           case required length will be returned in length argument.* @param[inout]  length     A non-zero pointer to the variable holding the length of out_value.*                           In case out_value a zero, will be set to the length*                           required to hold the value. In case out_value is not*                           zero, will be set to the actual length of the value*                           written. For nvs_get_str this includes zero terminator.** @return*             - ESP_OK if the value was retrieved successfully*             - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist*             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL*             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints*             - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data*/
/**@{*/
esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length);
esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length);

提交保存数据

/*** @brief      Write any pending changes to non-volatile storage** After setting any values, nvs_commit() must be called to ensure changes are written* to non-volatile storage. Individual implementations may write to storage at other times,* but this is not guaranteed.** @param[in]  handle  Storage handle obtained with nvs_open.*                     Handles that were opened read only cannot be used.** @return*             - ESP_OK if the changes have been written successfully*             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL*             - other error codes from the underlying storage driver*/
esp_err_t nvs_commit(nvs_handle handle);

不透明句柄

/*** Opaque pointer type representing non-volatile storage handle*/
typedef uint32_t nvs_handle;#define ESP_ERR_NVS_BASE                    0x1100                     /*!< Starting number of error codes */
#define ESP_ERR_NVS_NOT_INITIALIZED         (ESP_ERR_NVS_BASE + 0x01)  /*!< The storage driver is not initialized */
#define ESP_ERR_NVS_NOT_FOUND               (ESP_ERR_NVS_BASE + 0x02)  /*!< Id namespace doesn鈥檛 exist yet and mode is NVS_READONLY */
#define ESP_ERR_NVS_TYPE_MISMATCH           (ESP_ERR_NVS_BASE + 0x03)  /*!< The type of set or get operation doesn't match the type of value stored in NVS */
#define ESP_ERR_NVS_READ_ONLY               (ESP_ERR_NVS_BASE + 0x04)  /*!< Storage handle was opened as read only */
#define ESP_ERR_NVS_NOT_ENOUGH_SPACE        (ESP_ERR_NVS_BASE + 0x05)  /*!< There is not enough space in the underlying storage to save the value */
#define ESP_ERR_NVS_INVALID_NAME            (ESP_ERR_NVS_BASE + 0x06)  /*!< Namespace name doesn鈥檛 satisfy constraints */
#define ESP_ERR_NVS_INVALID_HANDLE          (ESP_ERR_NVS_BASE + 0x07)  /*!< Handle has been closed or is NULL */
#define ESP_ERR_NVS_REMOVE_FAILED           (ESP_ERR_NVS_BASE + 0x08)  /*!< The value wasn鈥檛 updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn鈥檛 fail again. */
#define ESP_ERR_NVS_KEY_TOO_LONG            (ESP_ERR_NVS_BASE + 0x09)  /*!< Key name is too long */
#define ESP_ERR_NVS_PAGE_FULL               (ESP_ERR_NVS_BASE + 0x0a)  /*!< Internal error; never returned by nvs API functions */
#define ESP_ERR_NVS_INVALID_STATE           (ESP_ERR_NVS_BASE + 0x0b)  /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */
#define ESP_ERR_NVS_INVALID_LENGTH          (ESP_ERR_NVS_BASE + 0x0c)  /*!< String or blob length is not sufficient to store data */
#define ESP_ERR_NVS_NO_FREE_PAGES           (ESP_ERR_NVS_BASE + 0x0d)  /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */
#define ESP_ERR_NVS_VALUE_TOO_LONG          (ESP_ERR_NVS_BASE + 0x0e)  /*!< String or blob length is longer than supported by the implementation */
#define ESP_ERR_NVS_PART_NOT_FOUND          (ESP_ERR_NVS_BASE + 0x0f)  /*!< Partition with specified name is not found in the partition table */#define ESP_ERR_NVS_NEW_VERSION_FOUND       (ESP_ERR_NVS_BASE + 0x10)  /*!< NVS partition contains data in new format and cannot be recognized by this version of code */
#define ESP_ERR_NVS_XTS_ENCR_FAILED         (ESP_ERR_NVS_BASE + 0x11)  /*!< XTS encryption failed while writing NVS entry */
#define ESP_ERR_NVS_XTS_DECR_FAILED         (ESP_ERR_NVS_BASE + 0x12)  /*!< XTS decryption failed while reading NVS entry */
#define ESP_ERR_NVS_XTS_CFG_FAILED          (ESP_ERR_NVS_BASE + 0x13)  /*!< XTS configuration setting failed */
#define ESP_ERR_NVS_XTS_CFG_NOT_FOUND       (ESP_ERR_NVS_BASE + 0x14)  /*!< XTS configuration not found */
#define ESP_ERR_NVS_ENCR_NOT_SUPPORTED      (ESP_ERR_NVS_BASE + 0x15)  /*!< NVS encryption is not supported in this version */
#define ESP_ERR_NVS_KEYS_NOT_INITIALIZED    (ESP_ERR_NVS_BASE + 0x16)  /*!< NVS key partition is uninitialized */
#define ESP_ERR_NVS_CORRUPT_KEY_PART        (ESP_ERR_NVS_BASE + 0x17)  /*!< NVS key partition is corrupt */

例子(保存系统重启次数):

#include <Arduino.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"void setup()
{Serial.begin(9600);// 初始化NVSesp_err_t err = nvs_flash_init();if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {// NVS partition was truncated and needs to be erased// Retry nvs_flash_initESP_ERROR_CHECK(nvs_flash_erase());err = nvs_flash_init();}ESP_ERROR_CHECK( err );// Openprintf("\n");printf("Opening Non-Volatile Storage (NVS) handle... ");nvs_handle_t my_handle;err = nvs_open("storage", NVS_READWRITE, &my_handle);if (err != ESP_OK) {printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));} else {printf("Done\n");// Readprintf("Reading restart counter from NVS ... ");int32_t restart_counter = 0; // value will default to 0, if not set yet in NVSerr = nvs_get_i32(my_handle, "restart_counter", &restart_counter);switch (err) {case ESP_OK:printf("Done\n");printf("Restart counter = %d\n", restart_counter);break;case ESP_ERR_NVS_NOT_FOUND:printf("The value is not initialized yet!\n");break;default :printf("Error (%s) reading!\n", esp_err_to_name(err));}// Writeprintf("Updating restart counter in NVS ... ");restart_counter++;err = nvs_set_i32(my_handle, "restart_counter", restart_counter);printf((err != ESP_OK) ? "Failed!\n" : "Done\n");// Commit written value.// After setting any values, nvs_commit() must be called to ensure changes are written// to flash storage. Implementations may write to storage at other times,// but this is not guaranteed.printf("Committing updates in NVS ... ");err = nvs_commit(my_handle);printf((err != ESP_OK) ? "Failed!\n" : "Done\n");// Closenvs_close(my_handle);}printf("\n");// Restart modulefor (int i = 10; i >= 0; i--) {printf("Restarting in %d seconds...\n", i);vTaskDelay(1000 / portTICK_PERIOD_MS);}printf("Restarting now.\n");fflush(stdout);esp_restart();
}void loop()
{
80   delay(0xFFFFFF);
}

资料来源:

  ESP32编程指南

  nvs介绍

ESP32-NVS存储(非易失性存储库)相关推荐

  1. ESP32开发--使用NVS存储数据

    ESP32基础系列 ESP32初体验之环境搭建 ESP32外设学习之GPIO ESP32外设学习之UART ESP32开发之给模块连上网络 ESP32的一键配网与Airkiss配网 ESP32使用NV ...

  2. ESP32数据存储 nvs

    这个实验的功能是使用乐鑫提供的 nvs 库去对 spi flash 的读写. 这个实验的代码为工程"3_9_nvs"目录. 3.9.1. 实验内容 (1) 学习 NVS 库函数接口 ...

  3. Arduino框架下对ESP32 NVS非易失性存储解读以及应用示例

    Arduino框架下对ESP32 NVS非易失性存储解读以及应用示例 NVS非易失性存储库介绍 非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据.本文档将详细介绍 NVS 常用 ...

  4. ESP32 NVS同windows文件系统的类比,附上一段NVS操作的代码解析

    ESP32 NVS同windows文件系统的类比,附上一段NVS操作的代码解析 下面例程是在NVS区域记录ESP32重启次数. 源码是改写Hello_world官方例程: #include <s ...

  5. ESP32 通过NVS存储WiFi账号和密码至Flash

    前言 项目需求:在ESP32板子重启之后,自动从Flash中寻找已经存储好的WiFi账号和秘密,连接到网络. 要想能够很好的理解如何将WiFi的账号和密码如何写入到Flash的什么地方,首先需要了解下 ...

  6. ESP32专栏八 NVS存储

    NVS Blob块存储 1. 演示app_main任务栈溢出 2. 设置app_main任务栈大小 打开menuconfig,输入main,如下图所示 默认栈大小为3584字节,这里改为35840字节 ...

  7. ESP32-C3入门教程 基础篇(八、NVS — 非易失性存储库的使用)

    前面的7节课把开发板上基本的外设都测试过一边,接下来马上就要进入wifi和蓝牙应用的测试了 在此之前,还需要把掉电数据保存的功能给实现,在STM32中,可以使用内部的flash或者有些自带的EEPRO ...

  8. ESP32用NVS存储wifi信息

    通俗来说,NVS 就是在 flash 上分配的一块内存空间 ,提供给用户保存掉电不丢失的数据. 非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据. NVS适合存储一些小数据,如 ...

  9. ESP8266/ESP32 NVS 基本操作

    NVS 介绍 NVS: Non-volatile storage , 即将数据存储到 flash 中, 掉电或重启后数据仍然存在,  flash 类似于 PC 上磁盘. ESP8266 和 ESP32 ...

最新文章

  1. object转成实体对象_程序员的浪漫,new一个对象
  2. 二维数组中的查找问题
  3. php缓存实例,一个PHP缓存类实例
  4. Web Service 简单实例(java 版本) ,IDE自动生成客户端代码方法
  5. 灰度测试试验流量“洗牌”
  6. 肯耐珂萨助力世界500强零售企业在线春招:单次面试3000人
  7. 数学建模学习笔记(九)——聚类模型
  8. 零基础 | 入行软件测试,你想知道的都在这里了
  9. 【Kafka】测试Kafka整合Flume
  10. 设置webstorm实时预览看这一篇就够了,5分钟解决!!
  11. ftp 上传文件夹_8uftp上传工具,8uftp上传工具的使用方法
  12. 将多个csv文件整合到一个csv文件中
  13. hadoop命令使用put上传文件报错
  14. 笔记篇二:鸢尾花数据集分类
  15. mysql双机备份最简单_简单实现mysql双机热备份
  16. 数模优秀论文分析(国赛C题)
  17. 《炬丰科技-半导体工艺》SC-1颗粒去除和piranha后漂洗的机理研究
  18. FISCO BCOS最强学习路径,汇聚全网资源(2022更新版)
  19. linux下调用pyd文件,linux pyd
  20. 多周期CPU设计(verilog)

热门文章

  1. DEEPIN系统安装各个版本的R语言
  2. 将Windows10设置为UTF8编码格式
  3. 输入年月判断这个月有多少天
  4. ArcGIS制图之阴影效果的表达与运用
  5. Wps日期时间格式转文本、科学计数法转数字
  6. 基于上下文的业务流建模法(二)
  7. CTF入门学习思维导图
  8. 名帖128 成亲王 楷书《心经》册
  9. Win硬件 - 西部数据绿盘、蓝盘、黑盘、红盘和紫盘有什么区别?
  10. บาคาร่า ธุรกิจที่สร้างรายได้ดี