【NodeMCU实时天气时钟温湿度项目 7】和风天气API返回JSON数据信息的解压缩实现——ArduinoUZlib功能库

        今天是第七专题,主要内容是:导入ArduinoUZlib功能库,借助该库把从【和风天气】官网返回的经过Gzip压缩的JSON数据,进行解压缩和t解析,在串口监视器上输出解析后的JSON信息。

        如您需要了解其它专题的内容,请点击下面的链接。
        第一专题内容,请参考:连接点亮SPI-TFT屏幕和UI布局设计
        第二专题内容,请参考:WIFI模式设置及连接
        第三专题内容,请参考:连接SHT30传感器,获取并显示当前环境温湿度数据(I2C)
        第四专题内容,请参考:通过NTPClient库获取实时网络时间并显示在TFT屏幕上
        第五专题内容,请参考:获取关于城市天气实况和天气预报的JSON信息(心知天气版)
        第六专题内容,请参考:解析天气信息JSON数据并显示在 TFT 屏幕上(心知天气版)

一、【心知天气】官网JSON数据特点

        1、订阅模式。和风天气开发服务采用订阅模式,当你创建项目时,至少需要选择一种订阅。使用和风天气的服务订阅非常简单和自由,免费或者你只需要为你实际使用的部分付费。现有三种订阅模式:免费订阅、标准订阅、高级订阅。
        每种订阅模式均可获取完整的天气信息数据。区别主要体现在数据请求量和更新频率方面。


        2、经过压缩的JSON数据。通过官网API接口返回的JSON数据,是进行Gzip压缩后的JSON数据,客户端需要先进行解压缩,然后再借助ArduinoJson功能库解析出解压缩后JSON数据,比心知天气返回JSON数据增加了一个解压缩过程。
        3、获取和风天气数据的方法。如果需要获得通过官网API接口返回的天气信息数据,需要首先心知天气注册账号、创建项目、选择订阅模式,然后获取API访问密钥KEY。具体操作方法网上有很多文档可供参考,请自行查询,比如:如何获取和风天气Web API的KEY?

二、添加ArduinoUZlib功能库

        1. ArduinoUZlib 的功能。该库是从uzlib移植到Arduino框架的功能库,主要用来解压https请求服务器返回的gzip数据。这个库占用内存比较小。
        2. 添加库方法。该库暂时无法从 PlatformIO 界面  -------> Libraries 加入。
        具体方法是:(1)进入该库 Github 网站,下载 zip 压缩文件。

(2)解压 zip 文件,生 成ArduinoUZlib-main 文件夹。
        (3)将此文件夹复制到 项目目录下的 lib 文件夹内,就可以使用该库的全部功能了。

三、主要功能函数

        该库使用方法简单方便,主要是通过调用 ArduinoUZlib::decompress(inbuff, size, outbuf,outsize) 这个功能函数来实现。

size_t size = stream->available(); // 还剩下多少数据没有读完?
uint8_t inbuff[size]; // 准备一个数组来装流数据,有多少装多少
stream->readBytes(inbuff, size); // 将http流数据写入inbuff中
uint8_t *outbuf=NULL; //解压后的输出流
uint32_t outsize=0; // 解压后多大?在调用解压方法后会被赋值。
// 调用解压函数
int result=ArduinoUZlib::decompress(inbuff, size, outbuf,outsize);
// 输出解密后的数据到控制台。
Serial.write(outbuf,outsize);

        详细内容可参考该库 example 目录下的示例:StreamHttpsClientGzipDemo,用来解压缩返回的 gzip数据。       

/**StreamHTTPClient.inoCreated on: 24.05.2015*/
#include <ArduinoJson.h>
#include <Arduino.h>
#include "ArduinoUZlib.h" 
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>#include <ESP8266HTTPClient.h>
ESP8266WiFiMulti WiFiMulti;// ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getHeapSize(), ESP.getMaxAllocHeap()
void heap(){Serial.print("FREE_HEAP[");Serial.print(ESP.getFreeHeap());Serial.print("]\n");
}
void setup() {Serial.begin(115200);// Serial.setDebugOutput(true);Serial.println();Serial.println();Serial.println();for (uint8_t t = 4; t > 0; t--) {Serial.printf("[SETUP] WAIT %d...\n", t);Serial.flush();delay(1000);}WiFi.mode(WIFI_STA);WiFiMulti.addAP("ssid", "password");
}
void log(const char *str) {Serial.println(str);
}static uint8_t buffer[1280]={0};
size_t readBytesSize=0;void fetchBuffer() {if ((WiFiMulti.run() == WL_CONNECTED)) {std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);client->setInsecure();Serial.print("[HTTPS] begin...\n");HTTPClient https;if (https.begin(*client, "https://192.168.2.144:8082/test")) {https.addHeader("Accept-Encoding", "gzip");Serial.print("[HTTPS] GET...\n");// start connection and send HTTP headerint httpCode = https.GET();if (httpCode > 0) {// HTTP header has been send and Server response header has been handledSerial.printf("[HTTPS] GET... code: %d\n", httpCode);// file found at serverif (httpCode == HTTP_CODE_OK) {// get length of document (is -1 when Server sends no Content-Length header)int len = https.getSize();// create buffer for readstatic uint8_t buff[128] = { 0 };// read all data from serverint offset=0;Serial.println("allocate");//  为什么这里分配内存会报错?// if(inbuf==NULL) inbuf=(uint8_t*)malloc(sizeof(uint8_t)*128);while (https.connected() && (len > 0 || len == -1)) {// get available data sizesize_t size = client->available();if (size) {// read up to 128 byteint c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));// int c = client->readBytes(buff, size);// Serial.println("memcpy");memcpy(buffer+offset, buff, sizeof(uint8_t)*c);offset+=c;if(c>0 && c!=16) {log("======rb====");Serial.printf("%d,", buff[c-3]);Serial.printf("%d,", buff[c-2]);Serial.printf("%d,", buff[c-1]);log("\n======rb end====");}// write it to Serial// Serial.write(buff, c);if (len > 0) {len -= c;}}delay(1);}readBytesSize=offset;Serial.printf("offset=%d\n", offset);Serial.write(buffer, offset);Serial.print("[HTTPS] connection closed or file end.\n");}} else {Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());}https.end();} else {Serial.printf("Unable to connect\n");}}
}void loop() {uint8_t *outbuf1=NULL;// wait for WiFi connectionfetchBuffer();Serial.printf("\nAfter fetch, buffer size=%d\n", readBytesSize);delay(1000);if(readBytesSize) {// write it to Seriallog("===buf===");Serial.printf("%d,", readBytesSize-3);Serial.printf("%d,", readBytesSize-2);Serial.printf("%d,", readBytesSize-1);log("\n===buf end===");    Serial.write(buffer,readBytesSize);uint32_t out_size=0;int result=ArduinoUZlib::decompress(buffer, readBytesSize, outbuf1, out_size);printf("outsize=%d, result=\n", out_size,result);parseJSON((char*)outbuf1, out_size);// Serial.write(outbuf,out_size);}else {Serial.println("no avali size!");}
if (outbuf1!=NULL){free(outbuf1);outbuf1=NULL;
}Serial.println("Wait 10s before the next round...");delay(5000);
}void parseJSON(char *input, int inputLength) {// char* input;// size_t inputLength; (optional)DynamicJsonDocument doc(6144);DeserializationError error = deserializeJson(doc, input, inputLength);if (error) {Serial.print(F("deserializeJson() failed: "));Serial.println(error.f_str());return;}const char* code = doc["code"]; // "200"const char* updateTime = doc["updateTime"]; // "2022-12-05T15:35+08:00"const char* fxLink = doc["fxLink"]; // "http://hfx.link/1u0r1"for (JsonObject hourly_item : doc["hourly"].as<JsonArray>()) {// const char* hourly_item_fxTime = hourly_item["fxTime"]; // "2022-12-05T17:00+08:00", ...const char* hourly_item_fxTime = hourly_item["fxTime"]; // "2022-12-05T17:00+08:00", ...const char* hourly_item_temp = hourly_item["temp"]; // "15", "13", "13", "12", "11", "11", "10", "10", ...Serial.printf("%s,", hourly_item_temp);const char* hourly_item_icon = hourly_item["icon"]; // "100", "150", "150", "150", "150", "150", "150", ...const char* hourly_item_text = hourly_item["text"]; // "晴", "晴", "晴", "晴", "晴", "晴", "晴", "多云", "多云", ...const char* hourly_item_wind360 = hourly_item["wind360"]; // "22", "24", "30", "33", "33", "31", "30", ...const char* hourly_item_windDir = hourly_item["windDir"]; // "东北风", "东北风", "东北风", "东北风", "东北风", "东北风", ...const char* hourly_item_windScale = hourly_item["windScale"]; // "3-4", "3-4", "3-4", "3-4", "3-4", ...const char* hourly_item_windSpeed = hourly_item["windSpeed"]; // "16", "16", "16", "16", "14", "14", ...const char* hourly_item_humidity = hourly_item["humidity"]; // "57", "63", "63", "65", "66", "67", "68", ...const char* hourly_item_pop = hourly_item["pop"]; // "1", "3", "6", "6", "6", "6", "6", "6", "7", "7", ...const char* hourly_item_precip = hourly_item["precip"]; // "0.0", "0.0", "0.0", "0.0", "0.0", "0.0", ...const char* hourly_item_pressure = hourly_item["pressure"]; // "1013", "1013", "1012", "1012", "1012", ...const char* hourly_item_cloud = hourly_item["cloud"]; // "5", "5", "4", "4", "7", "9", "11", "33", "54", ...const char* hourly_item_dew = hourly_item["dew"]; // "7", "6", "6", "6", "5", "5", "5", "5", "5", "4", ...}Serial.println();JsonArray refer_sources = doc["refer"]["sources"];const char* refer_sources_0 = refer_sources[0]; // "QWeather"const char* refer_sources_1 = refer_sources[1]; // "NMC"const char* refer_sources_2 = refer_sources[2]; // "ECMWF"const char* refer_license_0 = doc["refer"]["license"][0]; // "CC BY-SA 4.0"}

四、和风天气JSON数据的解压缩实现

        这是个实现解压缩和风天气JSON数据的简单示例:(1)将服务器进行Gzip压缩后返回的JSON数据,接收并保存到缓冲区 buffer 中;(2)调用 ArduinoUZlib::decompress(inbuffer, size, outbuffer,outsize) 解压 buffer 中的经过压缩的JSON数据,同时将解压后JSON数据保存到输出 outbuffer 中;(3)调用 ArduinoJson 库的 deserializeJson(doc, outbuffer) 函数,对明文JSON数据进行解析,并保存到实况天气数据结构 wd 中,然后通过串口监视器输出。
        具体内容,请仔细阅读下面的代码实现。

// 实时天气
struct weather_data
{int code = -1;               // API状态码,具体含义请参考状态码String updateTime = "";      // 当前API的最近更新时间String now_obsTime = "";     // 数据观测时间String now_temp = "0";       // 温度,默认单位:摄氏度int now_feelsLike = 0;       // 体感温度,默认单位:摄氏度String now_icon = "";        // 天气状况和图标的代码,图标可通过天气状况和图标下载String now_text = "";        // 天气状况的文字描述,包括阴晴雨雪等天气状态的描述String now_wind360 = "-1";   // 风向360角度String now_windDir = "";     // 风向String now_windScale = "-1"; // 风力等级int now_windSpeed = -1;      // 风速,公里/小时int now_humidity = -1;       // 相对湿度,百分比数值int now_precip = -1;         // 当前小时累计降水量,默认单位:毫米int now_pressure = -1;       // 大气压强,默认单位:百帕int now_vis = -1;            // 能见度,默认单位:公里
} wd;void get_now_weather_data(JsonDocument &doc);size_t readBytesSize = 0;// 用来存放解压前的JSON数据
static uint8_t buffer[1280] = {0};// 用来存放解压后的JSON数据
uint8_t *outbuffer = NULL;// 获取实时天气数据
void get_now_Weather()
{// 检查WIFI是否连接if ((WiFi.status() == WL_CONNECTED)){// 准备发起请求std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);client->setInsecure();Serial.print("[HTTPS] begin...\n");HTTPClient https;if (https.begin(*client, "https://devapi.qweather.com/v7/weather/now?key=" + key + "&location=" + cityid)){https.addHeader("Accept-Encoding", "gzip");Serial.print("[HTTPS] GET...\n");// start connection and send HTTP headerint httpCode = https.GET();if (httpCode > 0){// HTTP header has been send and Server response header has been handledSerial.printf("[HTTPS] GET... code: %d\n", httpCode);// file found at serverif (httpCode == HTTP_CODE_OK){// get length of document (is -1 when Server sends no Content-Length header)int len = https.getSize();// create buffer for readstatic uint8_t buff[128] = {0};// read all data from serverint offset = 0;//  为什么这里分配内存会报错?// if(inbuf==NULL) inbuf=(uint8_t*)malloc(sizeof(uint8_t)*128);while (https.connected() && (len > 0 || len == -1)){// get available data sizesize_t size = client->available();if (size){// read up to 128 byteint c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));memcpy(buffer + offset, buff, sizeof(uint8_t) * c);offset += c;// write it to Serial// Serial.write(buff, c);if (len > 0){len -= c;}}delay(1);}readBytesSize = offset;delay(1000);if (readBytesSize){// write it to SerialSerial.write(buffer, readBytesSize);Serial.println("");uint32_t out_size = 0;ArduinoUZlib::decompress(buffer, readBytesSize, outbuffer, out_size);Serial.write(outbuffer, out_size);// 调用解析函数JsonDocument doc;DeserializationError err = deserializeJson(doc, outbuffer);if (err.code() == DeserializationError::Ok){get_now_weather_data(doc);}else{Serial.println("数据解析出错");}}else{Serial.println("no avali size!");}if (outbuffer != NULL){free(outbuffer);outbuffer = NULL;}}}else{Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());}https.end();}else{Serial.printf("Unable to connect\n");}}
}void get_now_weather_data(JsonDocument &doc)
{// 将数据保存到weahter_data 的结构体,方便后续调用Serial.println("");wd.code = doc["code"];wd.updateTime = doc["updateTime"].as<String>().substring(0, 16);wd.now_obsTime = doc["now"]["obsTime"].as<String>().substring(0, 16);wd.updateTime.replace("T", " ");wd.now_obsTime.replace("T", " ");wd.now_temp = doc["now"]["temp"].as<String>();wd.now_feelsLike = doc["now"]["feelsLike"].as<int>();wd.now_icon = doc["now"]["icon"].as<String>();wd.now_text = doc["now"]["text"].as<String>();wd.now_wind360 = doc["now"]["wind360"].as<String>();wd.now_windDir = doc["now"]["windDir"].as<String>();wd.now_windScale = doc["now"]["windScale"].as<String>();wd.now_windSpeed = doc["now"]["windSpeed"].as<int>();wd.now_humidity = doc["now"]["humidity"].as<int>();wd.now_precip = doc["now"]["precip"].as<int>();wd.now_pressure = doc["now"]["pressure"].as<int>();wd.now_vis = doc["now"]["vis"].as<int>();Serial.print("wd.code: ");Serial.println(wd.code);Serial.print("wd.updateTime: ");Serial.println(wd.updateTime);Serial.print("wd.now_obsTime: ");Serial.println(wd.now_obsTime);Serial.print("wd.now_temp: ");Serial.println(wd.now_temp);Serial.print("wd.now_feelsLike: ");Serial.println(wd.now_feelsLike);Serial.print("wd.now_icon: ");Serial.println(wd.now_icon);Serial.print("wd.now_text: ");Serial.println(wd.now_text);Serial.print("wd.now_wind360: ");Serial.println(wd.now_wind360);Serial.print("wd.now_windDir: ");Serial.println(wd.now_windDir);Serial.print("wd.now_windScale: ");Serial.println(wd.now_windScale);Serial.print("wd.now_windSpeed: ");Serial.println(wd.now_windSpeed);Serial.print("wd.now_humidity: ");Serial.println(wd.now_humidity);Serial.print("wd.now_precip: ");Serial.println(wd.now_precip);Serial.print("wd.now_pressure: ");Serial.println(wd.now_pressure);Serial.print("wd.now_vis: ");Serial.println(wd.now_vis);
}

五、解压缩JSON数据源代码下载和运行效果展示

        百度网盘下载:UZlib_Qweather_CompressedJsonData_7,  提取码:ivfq
        友情提示:(1)请务必将 ssid 和 password 修改成您所在环境的名称和密码;(2)请务必const String key 修改成您自己申请的和风天气API密钥。
        如果您能在串口监视器看到如下信息,那么恭喜您程序运行成功了。
        

参考文档
1. JSON 基本使用_json怎么用-CSDN博客
2. 如何获取和风天气Web API的KEY?(简要步骤)_天气预报web api key-CSDN博客
3. JSON——概述、JSON语法、序列化和反序列化_所有文档都可以通过json序列化吗-CSDN博客

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

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

相关文章

C++:编程世界的永恒之石

在编程的广袤领域中&#xff0c;C犹如一块永恒的基石&#xff0c;历经岁月的洗礼&#xff0c;依旧坚固而璀璨。它的深厚底蕴、强大功能和广泛的应用领域&#xff0c;使其成为无数程序员心中的信仰与追求。 一、C&#xff1a;历史与传承的交汇点 C的历史可追溯到上世纪80年代&…

由于安全设置错误,远程桌面连接失败怎么办?

问题&#xff1a;远程桌面安全设置错误&#xff1f; “我是一名IT经理&#xff0c;需要经常使用远程桌面连接到办公室的电脑。近期&#xff0c;我在使用远程桌面时&#xff0c;远程桌面提示‘由于安全设置错误&#xff0c;客户端无法连接到远程计算机。’我不清楚是什么原因所…

哪些软件格式在win跟linux上都能运行?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 有一些软件格式在Windows和Li…

Windows snmp++获取本地主机信息

编译snmp的包 调用snmp.lib实现信息获取_哔哩哔哩_bilibili 代码&#xff1a; #include <iostream> #include <libsnmp.h> #include <vector> #include <fstream> #include <string> #include "snmp_pp/snmp_pp.h" //#define _NO_L…

基于django医用耗材网上申领系统的实现

基于django医用耗材网上申领系统的实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 管理员登录 系统在安全性的验证方面究竟做了什么功能呢&#xff1f;在做之前我们也进行了思量&…

开源go实现的iot物联网新基建平台

软件介绍 Magistrala IoT平台是由Abstract Machines公司开发的创新基础设施解决方案&#xff0c;旨在帮助组织和开发者构建安全、可扩展和创新的物联网应用程序。曾经被称为Mainflux的平台&#xff0c;现在已经开源&#xff0c;并在国际物联网领域受到广泛关注。 功能描述 多协…

re--SMC

参考&#xff1a;http://t.csdnimg.cn/g7fUY 参考&#xff1a;http://t.csdnimg.cn/qi3q5 简介 SMC&#xff0c;即Self Modifying Code&#xff0c;动态代码加密技术&#xff0c;指通过修改代码或数据&#xff0c;阻止别人直接静态分析&#xff0c;然后在动态运行程序时对代…

[动画详解]LeetCode151.翻转字符串里的单词

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到动画详解LeetCode算法系列 用通俗易懂的动画让算法题不再神秘 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读 如何低成…

pdf怎么标注红色方框?五种PDF标注红色方框方法

pdf怎么标注红色方框&#xff1f;在当今数字化时代&#xff0c;PDF文档已成为我们日常工作和学习中不可或缺的一部分。然而&#xff0c;如何在海量的PDF文件中快速、准确地标注出重要信息&#xff0c;让内容更加醒目呢&#xff1f;今天&#xff0c;我将向大家介绍五种PDF标注红…

DeepSort / Sort 区别

推荐两篇博文,详细介绍了deepsort的流程及代码大致讲解: https://blog.csdn.net/qq_48764574/article/details/138816891 https://zhuanlan.zhihu.com/p/196622890 DeepSort与Sort区别: 1、Sort 算法利用卡尔曼滤波算法预测检测框在下一帧的状态,将该状态与下一帧的检测结…

Context Pattern上下文模式

使用情景 全局使用的配置&#xff0c;数据库的连接。MVC中的跨层数据传输携带请求ID&#xff0c;用户信息等用户权限信息线程上下文 跨层数据共享 统一调用参数 携带多个事务需要处理的对象 携带用户信息 使用ThreadLocal

如何写好设计文档

一、明确目的 在编写设计文档之前&#xff0c;首先要明确为什么需要写这份文档。设计文档是软件开发过程中的重要沟通工具&#xff0c;它有助于确保团队成员对项目有共同的理解&#xff0c;促进协作&#xff0c;便于变更管理&#xff0c;并提供历史记录。 二、编写方法 为目…

网络工程师----第二十八天

计算机基础 第五章&#xff1a;运输层 运输层的两个协议&#xff1a; 1、传输控制协议TCP&#xff1a; TCP最主要的特点&#xff1a; (1)TCP是面向连接的。应用程序在使用TCP协议之前&#xff0c;必须先建立连接。在传送数据完毕后&#xff0c;必须释放已经建立的TCP连接。…

Mimikatz安装 lsass进程 SAM NTML

目录 什么是Mimikatz Mimikatz在windows上安装及使用 mimkatz语法 lsass进程 SAM NTML 什么是Mimikatz Mimikatz是一款开源的Windows安全工具&#xff0c;由法国安全研究员Benjamin Delpy开发。它最初被设计为用于学习C语言和进行Windows安全性实验的工具。然而&#xf…

Linux第四节--常见的指令介绍集合(持续更新中)

点赞关注不迷路&#xff01;本节涉及初识Linux第四节&#xff0c;主要为常见的几条指令介绍。 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1f44d;&#x1f3fb; 收藏 ✨ 加关注&#x1f440; 期待与你共同进步! 1. more指令 语法&#xff1a;more [选项][文件]…

AuroraFOC使用指南一(STM32F405双路FOC)

一. 简介 哈喽&#xff0c;感谢各位选择AuroraFOC开发板&#xff0c;在这里将对其进行一个详细的介绍&#xff0c;方便大家使用。并且对提供的工程文件和上位机的操作也进行了详细的说明。 有什么疑问或者好的建议 可以微信联系: WU1356742146 最后再次感谢大家的支持。 Aur…

SpringBoot实现 QQ邮箱验证码

SpringBoot实现 QQ邮箱验证码 文章目录 SpringBoot实现 QQ邮箱验证码一、开通SMTP校验码1.登录qq邮箱2.开启SMTP服务3.发送手机短信4.得到授权码 二、回到spring项目中1.导入所需依赖2.验证码工具类3.具体实现逻辑(serviceimpl) 三、测试qq邮箱验证码 一、开通SMTP校验码 1.登…

数据不平衡:使用其他机器学习方案,修改算法

数据不平衡&#xff1a; 神经网络在面对不均衡数据时&#xff0c;是束手无策的。有些机器学习方法&#xff0c;像决策树就不会受到不均衡数据的影响。 修改算法&#xff1a; 梨是多数派&#xff0c;需要调整门槛位置&#xff0c;使得更偏向于苹果。只有非常置信的时候&#x…

15-ps命令

常用选项 aux axjf a&#xff1a;显示一个终端所有的进程u&#xff1a;显示进程的归属用户及内存使用情况x&#xff1a;显示没有关联控制终端j&#xff1a;显示进程归属的进程组idf&#xff1a;以ASCII码的形式显示出进程的层次关系 ps aux其中| more是只显示一部分内容&…

iOS——runtime

什么是runtime 我们都知道&#xff0c;将源代码转换为可执行的程序&#xff0c;通常要经过三个步骤&#xff1a;编译、链接、运行。 C 语言 作为一门静态类语言&#xff0c;在编译阶段就已经确定了所有变量的数据类型&#xff0c;同时也确定好了要调用的函数&#xff0c;以及函…