700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > qt5.8(c++)实现阿里云人脸识别云接口

qt5.8(c++)实现阿里云人脸识别云接口

时间:2021-11-24 19:48:48

相关推荐

qt5.8(c++)实现阿里云人脸识别云接口

阿里云提供了人脸识别的api,其示例除了c/c++,其他主流语言都有相应的实例。

本人由于项目债务和集成需要,需要用c/c++实现,若只是支持win/Linux平台,采用

acl_master源码库也可行,有需要的可参考《阿里云短信服务接口的c++实现》,

阿里云的短信服务接口与人脸识别在数据签名、加密等方面是一致的。

我当前项目由于跨平台支持android编译,所以采用了qt实现阿里云的人脸识别接口。

备注:若需要静态编译实现阿里云的人脸识别,可能 qt环境需要重新静态编译network模块,追加openssl静态编译支持,

更细节的实现可以参考《qt5.8_for_vs and openssl静态编译 》。

阿里云的人脸识别主要有两个难点,其一是,若你直接传输图片内容,需要对图片内容进行编码,其二是需要实现签名认证。

下面就如何实现阿里云的人脸属性识别的过程(人脸检测定位、人脸比对类似):

1)首先需要开通 阿里云 的人脸识别服务,下面是本人在阿里云的云产品通用代金券链接:

阿里云限量红包

开通服务后,进入 人脸识别的控制台,在其左侧栏目有个API调试,点击进去,这里标注的

请求地址是我们需要用到的,例如:https://dtplus-cn-shanghai./face/attribute

另外 Access Key ID和Access Key Secret在API调用也需要,在你的头像下的AccessKeys项点击进去获取即可。

2)阿里API说明手册指出,若图片内容指定url,需要你只身配备网络存储路径,采用阿里的OSS也是不错的选择,若直接传输图片内容,需要采用base64编码,刚好qt5.8就能直接实现,下面就直接传输本地图片内容进行阿里云人脸识别API调用,记得qt工程文件需要添加,

QT += network

示例代码:

QByteArray FaceDetectObject::Image_To_Base64(QString image_path){QImage image(image_path);QByteArray ba;QBuffer buf(&ba);image.save(&buf,"jpg");QByteArray hexed = ba.toBase64();buf.close();return hexed;}

3)关于人脸识别的通信接口的签名的细节要求查看官方说明文档《API校验规范》章节,其内容要求UTF-8和Base64编码,签名算法遵循RFC 2104HMAC-SHA1规范。

MD5转换示例代码:

QByteArray FaceDetectObject::getMD5(QByteArray bytes_){QCryptographicHash ch(QCryptographicHash::Md5);QByteArray ret;ch.addData(bytes_);ret = ch.result();return ret;}

HMACSha1算法示例代码:

QByteArray FaceDetectObject::HMACSha1(QByteArray key, QByteArray baseString){int blockSize = 64;// HMAC-SHA-1 block size, defined in SHA-1 standardif (key.length() > blockSize) { // if key is longer than block size (64), reduce key length with SHA-1 compressionkey = QCryptographicHash::hash(key, QCryptographicHash::Sha1);}QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "/"// ascii characters 0x36 ("6") and 0x5c ("/") are selected because they have large// Hamming distance (/wiki/Hamming_distance)for (int i = 0; i < key.length(); i++) {innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key lengthouterPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length}// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64QByteArray total = outerPadding;QByteArray part = innerPadding;part.append(baseString);total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);/// 注意——>把字符串hashed转换为Hex,内存中的ASCII码arrayFromHexStringQByteArray arrayFromHexString = QByteArray::fromHex(hashed.toHex());qDebug()<<"hmacSha1内存中的ASCII码 arrayFromHexString \n"<<arrayFromHexString.toHex();return arrayFromHexString;}

4)阿里云一般对于http协议的时间格式要求是GMT的

也就是QT里面的UTC格式, 实现 样例:

QLocale lo = QLocale::English;//设置QLocale为英文QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");

其通信协议需要openssl支持才能实现https请求,实现 样例:

QNetworkRequest request;QSslConfiguration config;config.setPeerVerifyMode(QSslSocket::VerifyNone);config.setProtocol(QSsl::TlsV1_0);request.setSslConfiguration(config);

5)实现阿里云的人脸属性识别请求,记得把key和密钥换成自己的:

void FaceDetectObject::do_post_al(QByteArray bytearray){qDebug()<<"img_bytearray_size="<<bytearray.size()<<"\n";// qDebug()<<"img_bytearray="<<bytearray.data()<<"\n";url = QUrl("https://dtplus-cn-shanghai./face/attribute",QUrl::TolerantMode);// url.toEncoded();qDebug() <<"url="<<url.url()<<"\n";QString ak_id = "**************";//you keyQString ak_secret = "**************************";//you secret/** http header 参数*/QString method = "POST";QString accept = "application/json";QString content_type = "application/json";QLocale lo = QLocale::English;//设置QLocale为英文QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");qDebug() <<"date = " << date <<"\n";//1.对body做MD5+BASE64加密QByteArray body = QString("{\"type\":\"1\",\"content\":\"%1\"}").arg(bytearray.data()).toLocal8Bit();qDebug() <<"body = " << body <<"\n";QByteArray bodyMd5 = getMD5(body);qDebug() <<"bodyMd5 = " << bodyMd5 <<"\n";QString bodyBase64 = bodyMd5.toBase64();qDebug() <<"bodyBase64 = " << bodyBase64 <<"\n";QString stringToSign = method + "\n" + accept + "\n" + bodyBase64 + "\n" + content_type + "\n" + date + "\n"+ url.path();qDebug() << "stringToSign="<<stringToSign<<"\n";// 2.计算 HMAC-SHA1QString signature = HMACSha1(ak_secret.toLocal8Bit(),stringToSign.toLocal8Bit()).toBase64();qDebug() << "signature="<<signature<<"\n";// 3.得到 authorization headerQString authHeader = "Dataplus " + ak_id + ":" + signature;qDebug() << "authHeader="<<authHeader<<"\n";QNetworkRequest request;// request.sslConfiguration().setPeerVerifyMode(QSslSocket::VerifyNone);// request.sslConfiguration().setProtocol(QSsl::TlsV1_0);QSslConfiguration config;config.setPeerVerifyMode(QSslSocket::VerifyNone);config.setProtocol(QSsl::TlsV1_0);request.setSslConfiguration(config);request.setUrl(url);request.setRawHeader(QByteArray("accept"), accept.toLocal8Bit());request.setHeader(QNetworkRequest::ContentTypeHeader,content_type);request.setRawHeader(QByteArray("date"), date.toLocal8Bit());request.setRawHeader(QByteArray("Authorization"), authHeader.toLocal8Bit());// request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动deletereply->deleteLater();}reply = manager->post(request,body);// connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT(slotError(QNetworkReply::NetworkError)));// connect(reply, SIGNAL(sslErrors(QList<QSslError>)),// this, SLOT(slotSslErrors(QList<QSslError>)));connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));qDebug() << "start post_al";}

备注:bytearray是base64的图片内容

6)请求返回的数据为JSON格式 描述,字段描述细节参考官方的人脸属性识别API 调用说明,内容有点多,我就不截图。

返回数据获取示例代码如下:

void FaceDetectObject::finishedReplay(){QByteArray bytes = reply->readAll();const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);reply->deleteLater();reply = Q_NULLPTR;if (!redirectionTarget.isNull()) {//如果网址跳转重新请求const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());qDebug()<<"redirectedUrl:"<<redirectedUrl.url()<<"\n";url = redirectedUrl;qDebug()<<"new_url="<<url.toString().toLocal8Bit()<<"\n";//写出新url,测试使用QFile f("url_.txt");//写出文件f.open(QFile::WriteOnly);f.write(url.toString().toLocal8Bit());f.close();return;}qDebug()<<"finished:\n";QString html_text = bytes;qDebug()<<"get ready,read size:"<<html_text.size();qDebug()<< "ret_html_text:\n"<<html_text<<"\n";//保存结果,测试使用QFile f("result.html");//写出文件f.open(QFile::WriteOnly);f.write(bytes);f.close();}

返回结果示例:

{"face_num":1,"face_rect":[391,365,94,127],"face_prob":[1.0],"pose":[5.843783378601074,-3.454075336456299,2.8692541122436523],"landmark_num":105,"landmark":[..展示需要删除..],"iris":[417.10675048828125,415.4582214355469,4.029685020446777,460.1661071777344,418.9272155761719,4.029685020446777],"gender":[0],"age":[28],"expression":[0],"glass":[0],"dense_fea_len":1024,"dense_fea":"[..展示需要删除..]","errno":0,"request_id":"3bad9b68-b337-4c07-8661-403178948a31"}

取得返回结果后就是 业务应用的范畴了,人脸检测定位、人脸比对实现类似。基于我的业务逻辑只需要脸数、性别、年龄、笑容,示例代码如下:

//输入参数来自:QByteArray bytes = reply->readAll();void FaceDetectObject::JsonDecode(QByteArray bytes){QJsonParseError json_error;QJsonDocument retVals = QJsonDocument::fromJson(bytes,&json_error);if(json_error.error == QJsonParseError::NoError){if(retVals.isObject()){int face_num_val=0 ;QVector<bool> genders;QVector<int> ages;QVector<bool> expressions;QJsonObject obj = retVals.object();if(obj.contains("face_num")){QJsonValue face_num_Json = obj.value("face_num");qDebug() <<"face_num_Json="<< face_num_Json.toInt()<<"\n";if(face_num_Json.isDouble()){face_num_val = face_num_Json.toInt();}}if(obj.contains("gender")){QJsonValue gender_Json = obj.value("gender");if(gender_Json.isArray()){QJsonArray gender_vals = gender_Json.toArray();qDebug() <<"gender_vals="<< gender_vals<<"\n";foreach (QJsonValue gval, gender_vals) {if(gval.isDouble())genders.push_back(gval.toInt()>0?true:false);}if(genders.size()!=face_num_val){qDebug() << QString("gender vector num(%1) is not map face_num(%2)!").arg(genders.size()).arg(face_num_val);}}else{qDebug() << "gender_Json value type is not map Array!";}}if(obj.contains("age")){QJsonValue age_Json = obj.value("age");if(age_Json.isArray()){QJsonArray age_vals = age_Json.toArray();qDebug() <<"age_vals="<< age_vals<<"\n";foreach (QJsonValue age_val, age_vals) {if(age_val.isDouble())ages.push_back(age_val.toInt());}if(ages.size()!=face_num_val){qDebug() << QString("ages vector num(%1) is not map face_num(%2)!").arg(ages.size()).arg(face_num_val);}}else{qDebug() << "age_Json value type is not map Array!";}}if(obj.contains("expression")){QJsonValue expression_Json = obj.value("expression");if(expression_Json.isArray()){QJsonArray expression_vals = expression_Json.toArray();qDebug() <<"expression_vals="<< expression_vals<<"\n";foreach (QJsonValue expression_val, expression_vals) {if(expression_val.isDouble())expressions.push_back(expression_val.toInt()>0?true:false);}if(expressions.size()!=face_num_val){qDebug() << QString("expressions vector num(%1) is not map face_num(%2)!").arg(expressions.size()).arg(face_num_val);}}else{qDebug() << "expression_Json value type is not map Array!";}}qDebug() << "face_num_val="<<face_num_val<<"\n"<< "genders="<<genders<<"\n"<< "ages="<<ages<<"\n"<< "expressions="<<expressions<<"\n";}}else{qDebug() << "QJsonDocument::fromJson fail:"<<json_error.errorString()<<"\n";}

下面给出本实例的完整通信接口供有需要的朋友,记得换成自己的key和密钥,由于是示例代码,很多地方未做优化和产品化考虑,请大家斟酌参考:

#ifndef FACEDETECTOBJECT_H#define FACEDETECTOBJECT_H#include <QObject>#include <QString>#include <QByteArray>#include <QImage>#include <QNetworkAccessManager>#include <QUrl>#include <QNetworkRequest>#include <QNetworkReply>class FaceDetectObject: public QObject{Q_OBJECTpublic:FaceDetectObject(QObject * parent = 0);~FaceDetectObject();private:QByteArray getMD5(QByteArray bytes_);QByteArray HMACSha1(QByteArray key, QByteArray baseString);QByteArray Image_To_Base64(QString image_path);QImage Base64_To_Image(QByteArray bytearray,QString save_Path);QByteArray Image_To_ByteArray(QString image_path);QImage ByteArray_To_Image(QByteArray bytearray,QString save_Path);public slots:void do_get();void do_post_img(QString imgFile);void do_post(QByteArray bytearray);void do_post_al(QByteArray bytearray);private slots:void finishedReplay();void slotError(QNetworkReply::NetworkError net_error);void downloadProgress(qint64 bytesSent, qint64 bytesTotal);private:QNetworkAccessManager *manager;QUrl url;QNetworkReply *reply;};#endif // FACEDETECTOBJECT_H

#include "facedetectobject.h"#include <QBuffer>#include <QCryptographicHash>#include <QDateTime>#include <QFile>#include <QSslConfiguration>#include <QSslSocket>#include <QDebug>FaceDetectObject::FaceDetectObject(QObject * parent): QObject(parent){// //test// QByteArray src = Image_To_ByteArray("fdtimg.jpg");// QImage dest = ByteArray_To_Image(src,"fdtimg_c.jpg");manager =new QNetworkAccessManager(this);url = QUrl("/");reply = Q_NULLPTR;}FaceDetectObject::~FaceDetectObject(){}void FaceDetectObject::do_get(){QNetworkRequest request;request.setUrl(url);if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动deletereply->deleteLater();}reply = manager->get(request);// connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT(slotError(QNetworkReply::NetworkError)));connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));qDebug() << "start get";}void FaceDetectObject::do_post_img(QString imgFile){qDebug()<<"do_post_img and imgfile="<<imgFile<<"\n";QByteArray imgByteArray = Image_To_Base64(imgFile);do_post_al(imgByteArray);}void FaceDetectObject::do_post(QByteArray bytearray){QNetworkRequest request;request.setUrl(url);request.setRawHeader("Content-Type","application/x-www-form-urlencoded");if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动deletereply->deleteLater();}reply = manager->post(request,bytearray);// connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT(slotError(QNetworkReply::NetworkError)));// connect(reply, SIGNAL(sslErrors(QList<QSslError>)),// this, SLOT(slotSslErrors(QList<QSslError>)));connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));qDebug() << "start post";}void FaceDetectObject::do_post_al(QByteArray bytearray){qDebug()<<"img_bytearray_size="<<bytearray.size()<<"\n";// qDebug()<<"img_bytearray="<<bytearray.data()<<"\n";url = QUrl("https://dtplus-cn-shanghai./face/attribute",QUrl::TolerantMode);// url.toEncoded();qDebug() <<"url="<<url.url()<<"\n";QString ak_id = "************"; //keyQString ak_secret = "*************************"; //secret/** http header 参数*/QString method = "POST";QString accept = "application/json";QString content_type = "application/json";QLocale lo = QLocale::English;//设置QLocale为英文QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");qDebug() <<"date = " << date <<"\n";//1.对body做MD5+BASE64加密QByteArray body = QString("{\"type\":\"1\",\"content\":\"%1\"}").arg(bytearray.data()).toLocal8Bit();qDebug() <<"body = " << body <<"\n";QByteArray bodyMd5 = getMD5(body);qDebug() <<"bodyMd5 = " << bodyMd5 <<"\n";QString bodyBase64 = bodyMd5.toBase64();qDebug() <<"bodyBase64 = " << bodyBase64 <<"\n";QString stringToSign = method + "\n" + accept + "\n" + bodyBase64 + "\n" + content_type + "\n" + date + "\n"+ url.path();qDebug() << "stringToSign="<<stringToSign<<"\n";// 2.计算 HMAC-SHA1QString signature = HMACSha1(ak_secret.toLocal8Bit(),stringToSign.toLocal8Bit()).toBase64();qDebug() << "signature="<<signature<<"\n";// 3.得到 authorization headerQString authHeader = "Dataplus " + ak_id + ":" + signature;qDebug() << "authHeader="<<authHeader<<"\n";QNetworkRequest request;// request.sslConfiguration().setPeerVerifyMode(QSslSocket::VerifyNone);// request.sslConfiguration().setProtocol(QSsl::TlsV1_0);QSslConfiguration config;config.setPeerVerifyMode(QSslSocket::VerifyNone);config.setProtocol(QSsl::TlsV1_0);request.setSslConfiguration(config);request.setUrl(url);request.setRawHeader(QByteArray("accept"), accept.toLocal8Bit());request.setHeader(QNetworkRequest::ContentTypeHeader,content_type);request.setRawHeader(QByteArray("date"), date.toLocal8Bit());request.setRawHeader(QByteArray("Authorization"), authHeader.toLocal8Bit());// request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动deletereply->deleteLater();}reply = manager->post(request,body);// connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT(slotError(QNetworkReply::NetworkError)));// connect(reply, SIGNAL(sslErrors(QList<QSslError>)),// this, SLOT(slotSslErrors(QList<QSslError>)));connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));qDebug() << "start post_al";}QByteArray FaceDetectObject::getMD5(QByteArray bytes_){QCryptographicHash ch(QCryptographicHash::Md5);QByteArray ret;ch.addData(bytes_);ret = ch.result();return ret;}QByteArray FaceDetectObject::HMACSha1(QByteArray key, QByteArray baseString){int blockSize = 64;// HMAC-SHA-1 block size, defined in SHA-1 standardif (key.length() > blockSize) { // if key is longer than block size (64), reduce key length with SHA-1 compressionkey = QCryptographicHash::hash(key, QCryptographicHash::Sha1);}QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "/"// ascii characters 0x36 ("6") and 0x5c ("/") are selected because they have large// Hamming distance (/wiki/Hamming_distance)for (int i = 0; i < key.length(); i++) {innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key lengthouterPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length}// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64QByteArray total = outerPadding;QByteArray part = innerPadding;part.append(baseString);total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);/// 注意——>把字符串hashed转换为Hex,内存中的ASCII码arrayFromHexStringQByteArray arrayFromHexString = QByteArray::fromHex(hashed.toHex());qDebug()<<"hmacSha1内存中的ASCII码 arrayFromHexString \n"<<arrayFromHexString.toHex();return arrayFromHexString;}QByteArray FaceDetectObject::Image_To_Base64(QString image_path){QImage image(image_path);QByteArray ba;QBuffer buf(&ba);image.save(&buf,"jpg");QByteArray hexed = ba.toBase64();buf.close();return hexed;}QImage FaceDetectObject::Base64_To_Image(QByteArray bytearray,QString save_Path){QByteArray Ret_bytearray;Ret_bytearray = QByteArray::fromBase64(bytearray);QBuffer buffer(&Ret_bytearray);buffer.open(QIODevice::WriteOnly);QImage imageresult;imageresult.loadFromData(Ret_bytearray);if(save_Path != ""){qDebug() <<"save" ;imageresult.save(save_Path);}return imageresult;}QByteArray FaceDetectObject::Image_To_ByteArray(QString image_path){qDebug()<<"image_path="<<image_path<<"\n";QImage image(image_path);QByteArray ba;QBuffer buf(&ba);image.save(&buf,"jpg");qDebug()<<"ba_size="<<ba.size()<<"\n";// qDebug()<<"ba="<<ba.data()<<"\n";buf.close();return ba;}QImage FaceDetectObject::ByteArray_To_Image(QByteArray bytearray,QString save_Path){QBuffer buffer(&bytearray);buffer.open(QIODevice::WriteOnly);QImage imageresult;imageresult.loadFromData(bytearray);if(save_Path != ""){qDebug() <<"save" ;imageresult.save(save_Path);}return imageresult;}void FaceDetectObject::finishedReplay(){QByteArray bytes = reply->readAll();const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);reply->deleteLater();reply = Q_NULLPTR;if (!redirectionTarget.isNull()) {//如果网址跳转重新请求const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());qDebug()<<"redirectedUrl:"<<redirectedUrl.url()<<"\n";url = redirectedUrl;qDebug()<<"new_url="<<url.toString().toLocal8Bit()<<"\n";//写出新url,测试使用QFile f("url_.txt");//写出文件f.open(QFile::WriteOnly);f.write(url.toString().toLocal8Bit());f.close();return;}qDebug()<<"finished:\n";QString html_text = bytes;qDebug()<<"get ready,read size:"<<html_text.size();qDebug()<< "ret_html_text:\n"<<html_text<<"\n";//保存结果,测试使用QFile f("result.html");//写出文件f.open(QFile::WriteOnly);f.write(bytes);f.close();}void FaceDetectObject::slotError(QNetworkReply::NetworkError net_error){qDebug()<< "slotError:"<<net_error;}void FaceDetectObject::downloadProgress(qint64 bytesSent, qint64 bytesTotal){qDebug()<< "\ndownloadProgress done:\n";qDebug() << "bytesSent: " << bytesSent<< " " << "bytesTocal: " << bytesTotal;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。