内容简介

在《Qt 5.9 与 matlab 2017b 混合编程基本流程》里介绍了MATLAB与C++混合编程的基本流程,流程走通之后,关键就是通过DLL里的函数实现功能了。

MATLAB编译后的函数具有统一的输入输出参数的接口形式,主要是用到mwArray类型数组。在前一博文里没有对mwArray详细介绍,实际使用中还有些细节的问题,在本文里就对mwArray的使用做义工详细的介绍。

主要的内容包括:

(1)       mwArray数组的创建,设置实数数据

(2)       mwArray主要函数方法

(3)       给mwArray数组传递复数数据

(4)       给mwArray数组传递字符串数据

Qt 5.9 测试项目运行界面如下图所示,用到的工具和环境是:

matlab 2017b
      Qt 5.9
      MSVC 2015 64位编译器
      Windows 7  64位

1. 准备m文件,并编译生成DLL

在Matlab里编写三个m函数文件

function  C= matAdd(A,B)
% C= matAdd(A,B),  两个矩阵相加
C=A+B;
end

function  [C]= matAbs(A)
% 求矩阵各元素的绝对值或模, 若A为复数矩阵,求各个元素的模
C=abs(A);
end

function  [C]= matLoadDataFile(filename)
% 从一个文件载入数组
C=load(filename);
end

注意,这三个函数需要分别保存为m文件。

使用deploytool启动MATLAB Compiler,加入这3个m文件,编译为C++ Shared Library。编译项目保存为matBasics.prj,编译后的\for_redistribution_files_only目录下的文件如下图

2. Qt项目里使用matBasics.dll

2.1 Qt项目创建与.pro文件设置

在Qt Creator里创建一个Qt Widget Application,项目名称为test1,主窗口基于QMainWindow。在项目的文件目录下创建一个\include目录,将matBasics.h和matBasics.lib文件复制到此。

通过Add  Library 导入库文件matBasics.lib,并添加Matlab相关的库文件和头文件搜索路径。设MATLAB 2017b安装在D:\MATLAB 2017b目录下,设置后的test1.pro文件如下:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = test1
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        MainWindow.cpp \

HEADERS += \
        MainWindow.h \
    include/matBasics.h \

FORMS += \
        MainWindow.ui

#用户自定义的MATLAB程序的DLL库
win32: LIBS += -L$$PWD/include/ -lmatBasics

INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include

# Matlab 运行库的头文件
# .h文件搜索路径
INCLUDEPATH += D:/MATLAB2017b/extern/include
INCLUDEPATH += D:/MATLAB2017b/extern/include/Win64

# 用到的MATLAB 的.lib库文件
INCLUDEPATH += D:/MATLAB2017b/extern/lib/win64/microsoft
DEPENDPATH += D:/MATLAB2017b/extern/lib/win64/microsoft

win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -llibmex
win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -llibmx
win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -llibmat
win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -llibeng
win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -lmclmcr
win32: LIBS += -LD:/MATLAB2017b/extern/lib/win64/microsoft/ -lmclmcrrt

2.2  matBasics.dll的初始化

在使用matBasics.dll里的函数之前,需要调用matBasics.h里的函数matBasicsInitialize()进行初始化,我们将初始化在窗口的构造函数里完成。下面是构造函数的代码:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),   ui(new Ui::MainWindow){   ui->setupUi(this);    if (matBasicsInitialize()) //必须调用初始化      ui->plainTextEdit->appendPlainText("matlab程序DLL初始化成功.");   else   {      ui->plainTextEdit->appendPlainText("*** matlab程序DLL初始化失败");      return;   }   qsrand(QTime::currentTime().msec()); //初始化随机数种子}

3.  mwArray类的使用

3.1 mwArray类变量的常用构造函数

mwArray类常用的构造函数如下:

mwArray(mwSizenum_rows,mwSizenum_cols,mxClassIDmxID,mxComplexitycmplx=mxREAL)

num_rows表示行数, mwSize是整数类型
      num_cols表示列数
      mxID是mxClassID类型,表示元素的基本数据类型,常见的有如下的一些取值
    mxLOGICAL_CLASS,
    mxCHAR_CLASS,
    mxDOUBLE_CLASS,
    mxSINGLE_CLASS,
    mxINT8_CLASS,
    mxUINT8_CLASS,
    mxINT16_CLASS,
    mxUINT16_CLASS,
    mxINT32_CLASS,
    mxUINT32_CLASS,
    mxINT64_CLASS,
    mxUINT64_CLASS,

cmplx是mxComplexity类型,有mxREAL和mxCOMPLEX两种取值,标书数组元素是实数或复数,缺省为mxREAL
3.2 mwArray类变量的定义、赋值和常用函数的意义

窗口上“矩阵A的参数”按钮的响应代码如下:

void MainWindow::on_btnParams_clicked(){// 求矩阵A的各种参数, 即mwArray类的主要函数的作用   int   rowCntA=ui->spinBoxA_Row->value();//行数   int   colCntA=ui->spinBoxA_Col->value();//列数 //读取矩阵A   int   elementCntA=rowCntA*colCntA;//元素个数   double   *arrayA=new double[elementCntA]; //一维数组    int N=0;//一维数组的元素索引号   for(int i=0;i<ui->tableA->columnCount();i++) //逐列读取,按列存储      for (int j=0; j<ui->tableA->rowCount();j++)      {         arrayA[N]=ui->tableA->item(j,i)->text().toDouble();         N++;      }    mwArray matrixA(rowCntA,colCntA,mxDOUBLE_CLASS, mxREAL);//定义数组   matrixA.SetData(arrayA,elementCntA); //设置数据  //  mwArray类的主要函数的意义   ui->plainTextEdit->clear();   mwSize  dims=matrixA.NumberOfDimensions();//矩阵的维数,标量,值1=一维序列,2=二维数组   ui->plainTextEdit->appendPlainText(tr("mwArray::NumberOfDimensions() 矩阵的维数,标量"));   ui->plainTextEdit->appendPlainText(tr("       1 表示一维矩阵,  2 表示二维矩阵"));   ui->plainTextEdit->appendPlainText(tr("  matrixA.NumberOfDimensions()=%1").arg(dims));    mwArray arrayDim=matrixA.GetDimensions();//是个一维数组,元素个数=NumberOfDimensions()   ui->plainTextEdit->appendPlainText(tr("\n mwArray::GetDimensions()是矩阵的具体大小,即行数和列数"));   ui->plainTextEdit->appendPlainText("  matrixA.GetDimensions()的结果:");   for(int i=1;i<=dims;i++)   {      int cnt=arrayDim.Get(dims,i);//即使dims=2, i 表示元素索引,也是可行的//      int cnt=arrayDim.Get(1,i); //一维向量      ui->plainTextEdit->appendPlainText(tr("  第%1维大小 = %2").arg(i).arg(cnt));   }    mwSize   elementCnt=matrixA.NumberOfElements();//元素个数   ui->plainTextEdit->appendPlainText(tr("\n mwArray::NumberOfElements() 元素个数=行数*列数"));   ui->plainTextEdit->appendPlainText(tr("  matrixA.NumberOfElements()=%1").arg(elementCnt));}

这里,主要需要注意以下问题:

(1)mwArray数组的赋值

mwArray:: SetData(mxUint64* buffer, mwSizelen) 用于给数组赋值

其中,buffer必须是一维数组,即便mwArray变量是一个二维数组,len是一维数组的元素个数,等于行数乘以列数。在给二维数组赋值时,buffer必须按列存储数据(见代码内容)

(2)mwSize  mwArray::NumberOfDimensions()函数返回一个整数标量,表示数组的维数

返回值为1表示一维数组,2表示二维数组。

程序测试各种情况下都返回2,即便是一个行向量或列向量。

(3)mwArray   mwArray ::GetDimensions()返回一个数组,表示数组各维数的大小,对于向量或二维数组,返回值都是两个元素。第1个元素表示行数,第2个元素表示列数。

(4)mwSize   mwArray::NumberOfElements() 返回数组的元素个数,等于行数乘以列数

(5)mwArray的其他常用函数

bool  IsComplex() const  返回值表示数组是不是复数类型

bool  IsEmpty() const  返回值表示数组是否为空

bool  IsNumeric() const 返回值表示矩阵是否为数值型

1行1列的数组的参数

1行4列的数组的参数

3行1列的数组的参数

3.3 mwArray数组数据的读取

界面上“C=A”按钮的响应代码如下,其功能是将数组A直接复制给数组C,并读取出C的内容进行显示。

void MainWindow::on_btnAssign_clicked(){//C=A,用操作符赋值   int   rowCnt=ui->spinBoxA_Row->value();   int   colCnt=ui->spinBoxA_Col->value();    int elementCnt=rowCnt*colCnt;//元素个数   mwArray matrixA(rowCnt,colCnt,mxDOUBLE_CLASS, mxREAL);//定义数组,2行,3列,double类型 //读取数组A,   double   *arrayA;   arrayA=new double[elementCnt];    int N=0;   for(int i=0;i<ui->tableA->columnCount();i++)      for (int j=0; j<ui->tableA->rowCount();j++)      {//         matrixA(j,i)=ui->tableA->item(j,i)->text().toDouble(); //不能如此赋值         arrayA[N]=ui->tableA->item(j,i)->text().toDouble();         N++;      }    matrixA.SetData(arrayA,elementCnt); //读取结果//   mwArray matrixC(rowCnt,colCnt,mxDOUBLE_CLASS, mxREAL);//定义数组,2行,3列,double类型    mwArray  matrixC=matrixA;    ui->spinBoxC_Row->setValue(rowCnt);   ui->spinBoxC_Col->setValue(colCnt);    int dim=2; //数组维数,表示二维数组   N=1;   for(int i=1; i<=colCnt;i++)      for(int j=1; j<=rowCnt;j++)      {//         double   value=matrixC(j,i); //直接用数组下标索引,第j行,第i列//         double   value=matrixC(N); //直接按元素序号读取,第N个元素//         double   value=matrixA.Get(dim,j,i); //按照dim维数数组读出,获取第j行,第i列的数据         double   value=matrixA.Get(dim,N); //按照dim维数数组读出,读取序号为N的元素         N++;          QTableWidgetItem *item=new QTableWidgetItem(QString::asprintf("%.0f",value));         item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);         ui->tableC->setItem(j-1,i-1,item);      }}

这段代码注意以下问题:

(1)matrixA使用了SetData()函数赋值

mwArray matrixA(rowCnt,colCnt,mxDOUBLE_CLASS, mxREAL);   matrixA.SetData(arrayA,elementCnt);

(2)matrixC直接用了mwArray 的“=”操作符赋值,即

mwArray  matrixC=matrixA;

(3)mwArray数组元素的读取

可以使用mwArray::Get()函数读取数组的元素,

例如,对于二维数组,采用Get()函数读取数据的代码一般是

int dim=2; // 二维数组double   value=matrixA.Get(dim,j,i); //按照dim维数数组读出,第j行, 第i列

也可以不用行号、列号,而用序号读取,如

int dim=2; // 二维数组double   value=matrixA.Get(dim,N); //按照dim维数数组读出,第N个元素

这里的N是按列排列的元素的总的序号。对于二维数组,还是按照行号、列号更直观一些。

也可以直接使用mwArray的“()”操作符读取数组元素,如

double   value=matrixC(j,i); //直接用数组下标索引,第j行,第i列   double   value=matrixC(N); //直接按元素序号读取, 第N个元素

3.3 mwArray复数型数组赋值

mwArray也可以是复数性数组,定义数组时使用mxCOMPLEX 类型。

mwArray mwArray::real() 获取数组的实部,也是一个mwArray类型数组

mwArray mwArray::imag() 获取数组的虚部,也是一个mwArray类型数组

下面是界面上“A+B*j复数矩阵求模”按钮的响应代码,它将矩阵A作为复数矩阵的实部,矩阵B作为实数矩阵的虚部,然后代用DLL里的matAbs()函数求模。

void MainWindow::on_btnAbs_clicked(){// A+B*j复数矩阵求模   int   rowCntA=ui->spinBoxA_Row->value();   int   colCntA=ui->spinBoxA_Col->value();    int   rowCntB=ui->spinBoxB_Row->value();   int   colCntB=ui->spinBoxB_Col->value();    if ((rowCntA != rowCntB || (colCntA != colCntB)))   {      QMessageBox::critical(this, "错误", "矩阵A和B的维数不一致,不能构造复数矩阵",                            QMessageBox::Ok,QMessageBox::NoButton);      return;   } //读取矩阵A   int   elementCntA=rowCntA*colCntA;//元素个数   double   *arrayA=new double[elementCntA]; //一维数组    int N=0;//一维数组的元素索引号   for(int i=0;i<ui->tableA->columnCount();i++) //逐列读取,序列化存储到一维数组      for (int j=0; j<ui->tableA->rowCount();j++)      {         arrayA[N]=ui->tableA->item(j,i)->text().toDouble();         N++;      }    mwArray matrixComplex(rowCntA,colCntA,mxDOUBLE_CLASS, mxCOMPLEX);//定义数组,行,列,double类型复数矩阵   matrixComplex.Real().SetData(arrayA,elementCntA); //为复数矩阵的实部赋值 //读取数组B   int   elementCntB=rowCntB*colCntB;//元素个数   double   *arrayB=new double[elementCntB];    N=0;   for(int i=0;i<ui->tableB->columnCount();i++) //逐列读取,序列化存储到一维数组      for (int j=0; j<ui->tableB->rowCount();j++)      {         arrayB[N]=ui->tableB->item(j,i)->text().toDouble();         N++;      }    matrixComplex.Imag().SetData(arrayB,elementCntB); //为复数矩阵的虚部赋值 //计算, 复数矩阵的模  int   rowCntC=rowCntA;  int   colCntC=colCntA;    mwArray matrixAbs(rowCntC,colCntC,mxDOUBLE_CLASS, mxREAL);//定义数组,行,列,double类型   int nargout=1;//输出变量个数   matAbs(nargout,matrixAbs,matrixComplex); //读取结果   ui->spinBoxC_Row->setValue(rowCntC);   ui->spinBoxC_Col->setValue(colCntC);    int dim=2; //按照二维数组读出matrixC   for(int i=1; i<=colCntC;i++)      for(int j=1; j<=rowCntC;j++)      {         double   value=matrixAbs.Get(dim,j,i); //二维数组,第j行,第i列的数据         QTableWidgetItem *item=new QTableWidgetItem(QString::asprintf("%.4f",value));         item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);         ui->tableC->setItem(j-1,i-1,item);      }}

若是要读取复数型数组的内容,也是通过mwArray::real()和mwArray::imag()分别获取其实部和虚部数组,再读取元素的方法就是一样的了。

3.4 mwArray传递字符串数据

创建的matBasics.dll中的函数matLoadDataFile()是接收一个txt文件名,通过load指令载入文件,并作为数组返回。

function  [C]= matLoadDataFile(filename)
% 从一个文件载入数组
C=load(filename);
end

在matlab的指令窗口里生成一个随机数矩阵,并保存为文本文件

>> B=10*rand(3,4)
B =
       7.0936        6.797         1.19       3.4039
       7.5469        6.551       4.9836       5.8527
       2.7603       1.6261       9.5974       2.2381

>> save dataA.txt B -ascii

matBasics.h文件里的 matLoadDataFile()函数的原型是:

bool MW_CALL_CONV mlxMatLoadDataFile(int nlhs, mxArray *plhs[], int nrhs, mxArray    *prhs[]);

与其他接口函数的参数形式也是一样的,只是输入参数*prhs[] 需要传递字符串表示的文件名,返回数组plhs的行数、列数是未知的。

Qt 编写程序界面上的“打开数组txt文件”按钮的响应代码如下:

void MainWindow::on_btnOpenFile_clicked(){//传递字符串型数据    QString aFileName=QFileDialog::getOpenFileName(this,"打开文件","","txt文件(*.txt)");    if (aFileName.isEmpty())       return;     ui->plainTextEdit->clear();    ui->plainTextEdit->appendPlainText(aFileName); //打开文件,并在plainTextEdit里显示    QString str;    QFile aFile(aFileName);  //以文件方式读出    if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //以只读文本方式打开文件    {       QTextStream aStream(&aFile); //用文本流读取文件       while (!aStream.atEnd())       {          str=aStream.readLine();//读取文件的一行          ui->plainTextEdit->appendPlainText(str); //添加到文本框显示       }       aFile.close();//关闭文件    } //使用DLL里的matLoadDataFile()打开文件,并返回数组    char*   charStr=aFileName.toLocal8Bit().data();    mwArray matrixFilename(charStr);//字符串数据赋值     mwArray matrixC(mxDOUBLE_CLASS, mxREAL);//返回值是未知大小的数组    int nargout=1;//输出变量个数    matLoadDataFile(nargout,matrixC,matrixFilename); //读取结果数组    mwSize  dims=matrixC.NumberOfDimensions();//矩阵的维数,2表示二维数组    mwArray arrayDim=matrixC.GetDimensions();//各维的具体大小    int rowCnt=arrayDim.Get(dims,1); //行数    int colCnt=arrayDim.Get(dims,2); //列数     ui->spinBoxC_Row->setValue(rowCnt);    ui->spinBoxC_Col->setValue(colCnt);     for(int i=1; i<=colCnt;i++)       for(int j=1; j<=rowCnt;j++)       {          double   value=matrixC(j,i); //直接用数组下标索引,可行          QTableWidgetItem *item=new QTableWidgetItem(QString::asprintf("%.4f",value));          item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);          ui->tableC->setItem(j-1,i-1,item);       }}

这段代码先通过Qt的QFileDialog对话框选择文件并显示其内容,

这段代码要注意以下内容:

(1)字符串数据的mwArray数组的赋值

通过QFileDialog::getOpenFileName()获取需要打开的文件名aFileName,aFileName是QString类型,转换为char*类型变量charStr,定义数组matrixFilename时直接在构造函数里赋值。代码如下:

QString aFileName=QFileDialog::getOpenFileName(this,"打开文件","","txt文件(*.txt)");    char*   charStr=aFileName.toLocal8Bit().data();    mwArray matrixFilename(charStr);//字符串数据赋值

(2)未知行数、列数的mwArray的定义

调用matLoadDataFile()函数打开的数组的行列数是不确定的,所以定义返回数组matrixC时未指定行数和列数,定义和调用DLL里函数的代码如下:

mwArray matrixC(mxDOUBLE_CLASS, mxREAL);//返回值是未知大小的数组    int nargout=1;//输出变量个数    matLoadDataFile(nargout,matrixC,matrixFilename);

(3)未知大小的mwArray数组的数据读取

matrixC数组的大小预先是不知道的,调用matLoadDataFile()函数返回数组matrixC后,需要通过一些函数获取数组的行数和列数,才可以从数组里完整的读出数据。获取数组大小的代码如下:

mwSize  dims=matrixC.NumberOfDimensions();//矩阵的维数,2表示二维数组    mwArray arrayDim=matrixC.GetDimensions();//各维的具体大小     int rowCnt=arrayDim.Get(dims,1); //行数    int colCnt=arrayDim.Get(dims,2); //列数     ui->spinBoxC_Row->setValue(rowCnt);    ui->spinBoxC_Col->setValue(colCnt);

选择文件并打开后的运行效果如下图所示。

【本文实例Qt 5.9项目完整源程序下载地址】https://download.csdn.net/download/hongandyi/10416823

或百度网盘下载:  https://pan.baidu.com/s/1pM2PxrH

相关阅读:

Qt 5.9 与 matlab 2017b 混合编程基本流程

Matlab 2017b编译成exe或DLL文件后无法运行的问题及其解决方法
--------------------- 
作者:HongAndYi 
来源:CSDN 
原文:https://blog.csdn.net/HongAndYi/article/details/79477031 
版权声明:本文为博主原创文章,转载请附上博文链接!

Qt与Matlab混合编程中mwArray数组使用详解相关推荐

  1. QT与MATLAB混合编程

    QT与MATLAB混合编程 本文就介绍使用 Qt 和 Matlab 进行混合编程的基本流程,主要包括: 如何在Matlab中将m文件编译为C++语言的DLL文件 如何在Qt项目中加入自定义DLL相关的 ...

  2. Qt与Matlab混合编程细节总结

    最近准备做一个项目,其中要用到很复杂的拟合算法等,自己去实现这些算法要很久,而手边有师兄已经写好的Matlab函数,如果可以实现利用Qt调用这些函数,那么工作量将会减少很多.而且这个看上去也很简单,至 ...

  3. C#与Matlab混合编程中遇到的“MathWorks.MATLAB.NET.Arrays.MWNumericArray”的类型初始值设定项引发异常。

    C#与Matlab混合编程中遇到的"MathWorks.MATLAB.NET.Arrays.MWNumericArray"的类型初始值设定项引发异常. 参考文章: (1)C#与Ma ...

  4. Java多线程编程中Future模式的详解

    转载自 https://www.cnblogs.com/winkey4986/p/6203225.html Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker ...

  5. qt matlab环境配置文件,Qt与matlab混合编程

    由于项目需要,需要调用现有的matlab程序,考虑将matlab程序生成动态链接库,再在Qt下动态调用.在这个过程中,遇到了许多问题,写个文章mark一下. 1.环境准备 我的电脑是win10,也先装 ...

  6. 学习笔记:Qt与Matlab混合编程及遇到的诸多问题(附DEMO)

    工具:MATLAB R2014b,Qt 5.6.1, 目标:通过MATLAB写一个简单的函数,生成动态链接库DLL,再在Qt上调用 1.在MATLAB主页新建一个函数 记住函数的名字和保存的函数文件的 ...

  7. C++和MATLAB混合编程——初始化mwArray失败解决方法!

    首先,按这样设置, [填坑]VS2017与MATLAB2016b混合编程(生成dll方式)_清凉简装的博客-CSDN博客_matlab生成dllMATLAB 生成 dll 前的工作1.配置MATLAB ...

  8. Python面向对象编程(类编程)中self的含义详解(简单明了直击本质的解释)

    以下是博主认为的对self讲解得比较透彻又简洁明了的资料. 上面的资料把这个问题说得简单明了,大家认真看一遍相信就对self有个深入的了解了. 总结一下: 在Python为面向对象编程中,成员函数被调 ...

  9. Python中三维数组位置详解

    图示效果图: 直接贴代码: def test3D():import numpy as npdata_array = np.zeros((3, 5, 6), dtype=np.int)data_arra ...

  10. shell编程中crontab用法超级详解!

    使用crontab你可以在指定的时间执行一个shell脚本或者一系列Linux命令. 时间格式:{minute} {hour} {day-of-month} {month} {day-of-week} ...

最新文章

  1. 这些SpringBoot天生自带Buff工具类你都用过哪些?
  2. 从管道中飞出的不一定是炮弹,也可能是无人机
  3. 浅谈嵌套命名实体识别(Nested NER)
  4. Echart---多项柱状图-2D/H5
  5. 文献学习(part80-A)--Do we Need Hundreds of Classifiers to Solve Real World Classification Problems?
  6. startindex 不能大于字符串长度_「12」学习MySQL第二类函数:字符串函数
  7. 《Android应用开发攻略》——2.2 异常处理
  8. NTA告警引发的dll劫持思考(溯源)
  9. IDEA把console的输出写入到文件中
  10. H5+APP安卓原生插件开发+离线打包
  11. html答题游戏代码,html5+css3+ajax手机端脑筋急转弯答题游戏代码
  12. 硬件系统概要设计-1-信号完整性分析
  13. 论文中 一级标题、二级标题等 对应格式的统一修改
  14. EAS序时簿界面显示,不再忽略数值零
  15. 汉字的计算机输入法发展与历史,汉字输入的发展历程
  16. 民建李汉宇:运用大数据为监察体制改革插上科技翅膀
  17. php计算qqbkn,js解密之QQ的bkn值,获取QQ群成员信息,获取QQ好友列表信息
  18. 浅析SIEM、态势感知平台、安全运营中心
  19. Hypervisor定义、种类及产品介绍
  20. 专访|特赞CTO黄勇:微服务在互联网系统中如何实施?

热门文章

  1. 浅述Docker的容器编排
  2. 传奇服务器人物技能怎么修改,传奇服务端上线0级技能,直接设置3级技能的设置方法...
  3. 高并发系统中库存热点的解决方案
  4. 通过故障恢复控制台修复xp系统引导文件丢失的方法
  5. 【OUC深度学习入门】第4周学习记录:MobileNetV1, V2, V3
  6. 听吐的微信提示音终于能改了
  7. json解析天气预报java_Json解析-和风天气
  8. python大鱼吃小鱼单机游戏下载_大鱼吃小鱼
  9. 对本课程的期望以及教学建议
  10. linux 重命名文件夹