一、Qt中多线程的使用
在进行桌面应用程序开发的时候, 假设应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作。这种情况下就需要使用多线程,其中一个线程处理窗口事件,其他线程进行逻辑运算,多个线程各司其职,不仅可以提高用户体验还可以提升程序的执行效率。
1.在qt中使用了多线程,有些事项是需要额外注意的:
- 默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新
- 子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理
- 主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制(即如果子线程需要对窗口的数据进行修改,只能先通过connect发送给主线程,由主线程对窗口进行修改,而子线程不能直接对窗口进行修改)。
使用方式1
- 创建一个线程类的子类,让其继承QT中的线程类 QThread
- 重写父类的 run() 方法,在该函数内部编写子线程要处理的具体的业务流程
- 在主线程中创建子线程对象,new 一个就可以了
- 启动子线程, 调用 start() 方法
案例:创建一个子线程文件,里面定义三个子线程类,使其继承QThread,分别重写虚函数run,子线程需要执行的任务都写在该函数里面。而在主线程中,先创建该类的一个对象,调用start函数,则表示启动子线程(run()函数)。
下面创建了一个MyThread.h文件,在该文件里面创建了三个子线程类,分别是
- Generate类:生成随机数
- BubbleSort类:对生成的随机数进行冒泡排序
- QuickSort类:对生成的随机数进行快速排序
子线程头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class Generate : public QThread { Q_OBJECT public: explicit Generate(QObject *parent = nullptr); void recvNum(int num); protected: void run() override; signals: void sendArray(QVector<int>); private: int m_num; };
class BubbleSort : public QThread { Q_OBJECT public: explicit BubbleSort(QObject *parent = nullptr); void recvArray(QVector<int>list); protected: void run() override; signals: void finish(QVector<int> num); private: QVector<int> m_list; };
class QuickSort : public QThread { Q_OBJECT public: explicit QuickSort(QObject *parent = nullptr); void recvArray(QVector<int>list); protected: void run() override; private: void quick(QVector<int>&list, int l, int r); signals: void finish(QVector<int> num); private: QVector<int> m_list; };
|
主线程的头文件:
1 2 3 4 5 6 7 8 9 10 11
| class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); signals: void starting(int num); private: Ui::MainWindow *ui; };
|
子线程的执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| Generate::Generate(QObject *parent) : QThread(parent) { }
void Generate::recvNum(int num) { m_num = num; }
void Generate::run() { qDebug()<<"生成随机数的线程的线程地址:"<<QThread::currentThread(); QVector<int> list; QElapsedTimer time; time.start(); for(int i=0; i<m_num; i++){ list.push_back(qrand()%100000); } int milsec = time.elapsed(); qDebug()<<"生成"<<m_num<<"个随机数总共用时:"<<milsec<<"毫秒"; emit sendArray(list); }
BubbleSort::BubbleSort(QObject *parent):QThread(parent) { }
void BubbleSort::recvArray(QVector<int> list) { m_list = list; }
void BubbleSort::run() { qDebug()<<"冒泡排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); int temp; for(int i=0; i<m_list.size()-1; i++){ for(int j=0; j<m_list.size()-i-1; j++){ if(m_list[j]>m_list[j+1]){ temp = m_list[j]; m_list[j] = m_list[j+1]; m_list[j+1] = temp; } } } int milsec = time.elapsed(); qDebug()<<"冒泡排序花费的时间是"<<milsec<<"毫秒"; emit finish(m_list); }
QuickSort::QuickSort(QObject *parent):QThread(parent) { }
void QuickSort::recvArray(QVector<int> list) { m_list = list; }
void QuickSort::run() { qDebug()<<"快速排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); quick(m_list,0,m_list.size()-1); int milsec = time.elapsed(); qDebug()<<"快速排序花费的时间是"<<milsec<<"毫秒"; emit finish(m_list); }
void QuickSort::quick(QVector<int>&list, int l, int r) { if(l<r){ int i=l, j=r; int x = list[i]; while(i<j){ while(i<j && list[j]>=x) j--; list[i]=list[j]; while(i<j && list[i]<=x) i++; list[j]=list[i]; } list[i] = x; quick(list,l,i-1); quick(list,i+1,r); } }
|
主线程的执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this);
Generate* gen = new Generate; BubbleSort* bubble = new BubbleSort; QuickSort* quick = new QuickSort;
connect(this, &MainWindow::starting, gen, &Generate::recvNum);
connect(ui->start, &QPushButton::clicked, this, [=](){ emit starting(10000); gen->start(); }); connect(gen, &Generate::sendArray, bubble, &BubbleSort::recvArray); connect(gen, &Generate::sendArray, quick, &QuickSort::recvArray); connect(gen, &Generate::sendArray, this, [=](QVector<int> list){ bubble->start(); quick->start(); for(int i=0; i<list.size(); i++){ ui->randList->addItem(QString::number(list.at(i))); } }); connect(bubble, &BubbleSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->bubbleList->addItem(QString::number(list.at(i))); } }); connect(quick, &QuickSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->quickList->addItem(QString::number(list.at(i))); } }); }
|
执行结果:

使用方式2
Qt提供的第二种线程的创建方式弥补了第一种方式的缺点,用起来更加灵活,但是这种方式写起来会相对复杂一些。
- 创建一个新的类(如MyWork),让这个类从QObject派生
- 在这个类中添加一个公共的成员函数,如working(),函数体就是我们要子线程中执行的业务逻辑
- 在主线程中创建一个QThread对象, 这就是子线程的对象
- 在主线程中创建工作的类对象(千万不要指定给创建的对象指定父对象)
- 将MyWork对象移动到创建的子线程对象中, 需要调用QObject类提供的moveToThread()方法
- 启动子线程,调用 start(), 这时候线程启动了, 但是移动到线程中的对象(任务)并没有工作
- 调用MyWork类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的
主窗口的头文件:
1 2 3 4 5 6 7 8 9 10 11
| class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); signals: void starting(int num); private: Ui::MainWindow *ui; };
|
子类的头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Generate : public QObject { Q_OBJECT public: explicit Generate(QObject *parent = nullptr); void working(int num); signals: void sendArray(QVector<int>); };
class BubbleSort : public QObject { Q_OBJECT public: explicit BubbleSort(QObject *parent = nullptr); void working(QVector<int>list); signals: void finish(QVector<int> num); };
class QuickSort : public QObject { Q_OBJECT public: explicit QuickSort(QObject *parent = nullptr); void working(QVector<int>list); private: void quick(QVector<int>&list, int l, int r); signals: void finish(QVector<int> num); };
|
主函数执行函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this);
QThread* t1=new QThread; QThread* t2=new QThread; QThread* t3=new QThread;
Generate* gen = new Generate; BubbleSort* bubble = new BubbleSort; QuickSort* quick = new QuickSort;
gen->moveToThread(t1); bubble->moveToThread(t2); quick->moveToThread(t3);
connect(this, &MainWindow::starting, gen, &Generate::working);
connect(ui->start, &QPushButton::clicked, this, [=](){ emit starting(10000); t1->start(); }); connect(gen, &Generate::sendArray, bubble, &BubbleSort::working); connect(gen, &Generate::sendArray, quick, &QuickSort::working); connect(gen, &Generate::sendArray, this, [=](QVector<int> list){ t2->start(); t3->start(); for(int i=0; i<list.size(); i++){ ui->randList->addItem(QString::number(list.at(i))); } }); connect(bubble, &BubbleSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->bubbleList->addItem(QString::number(list.at(i))); } }); connect(quick, &QuickSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->quickList->addItem(QString::number(list.at(i))); } }); }
|
子类的执行函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| Generate::Generate(QObject *parent) : QObject(parent) { }
void Generate::working(int num) { qDebug()<<"生成随机数的线程的线程地址:"<<QThread::currentThread(); QVector<int> list; QElapsedTimer time; time.start(); for(int i=0; i<num; i++){ list.push_back(qrand()%100000); } int milsec = time.elapsed(); qDebug()<<"生成"<<num<<"个随机数总共用时:"<<milsec<<"毫秒"; emit sendArray(list); }
BubbleSort::BubbleSort(QObject *parent):QObject(parent) { }
void BubbleSort::working(QVector<int>list) { qDebug()<<"冒泡排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); int temp; for(int i=0; i<list.size()-1; i++){ for(int j=0; j<list.size()-i-1; j++){ if(list[j]>list[j+1]){ temp = list[j]; list[j] = list[j+1]; list[j+1] = temp; } } } int milsec = time.elapsed(); qDebug()<<"冒泡排序花费的时间是"<<milsec<<"毫秒"; emit finish(list); }
QuickSort::QuickSort(QObject *parent):QObject(parent) { }
void QuickSort::working(QVector<int>list) { qDebug()<<"快速排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); quick(list,0,list.size()-1); int milsec = time.elapsed(); qDebug()<<"快速排序花费的时间是"<<milsec<<"毫秒"; emit finish(list); }
void QuickSort::quick(QVector<int>&list, int l, int r) { if(l<r){ int i=l, j=r; int x = list[i]; while(i<j){ while(i<j && list[j]>=x) j--; list[i]=list[j]; while(i<j && list[i]<=x) i++; list[j]=list[i]; } list[i] = x; quick(list,l,i-1); quick(list,i+1,r); } }
|
二、线程池
在Qt中使用线程池需要先创建任务,添加到线程池中的每一个任务都需要是一个QRunnable类型,因此在程序中需要创建子类继承QRunnable这个类,然后重写 run() 方法,在这个函数中编写要在线程池中执行的任务,并将这个子类对象传递给线程池,这样任务就可以被线程池中的某个工作的线程处理掉了。
主线程的头文件:
1 2 3 4 5 6 7 8 9 10 11
| class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); signals: void starting(int num); private: Ui::MainWindow *ui; };
|
子线程的头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Generate : public QObject, public QRunnable { Q_OBJECT public: explicit Generate(QObject *parent = nullptr); void recvNum(int num); void run() override; signals: void sendArray(QVector<int>); private: int m_num; };
class BubbleSort : public QObject, public QRunnable { Q_OBJECT public: explicit BubbleSort(QObject *parent = nullptr); void recvArray(QVector<int>list); void run() override; signals: void finish(QVector<int> num); private: QVector<int> m_list; };
class QuickSort : public QObject, public QRunnable { Q_OBJECT public: explicit QuickSort(QObject *parent = nullptr); void recvArray(QVector<int>list); void run() override; private: void quick(QVector<int>&list, int l, int r); signals: void finish(QVector<int> num); private: QVector<int> m_list; };
|
主线程执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this);
Generate* gen = new Generate; BubbleSort* bubble = new BubbleSort; QuickSort* quick = new QuickSort; connect(this, &MainWindow::starting, gen, &Generate::recvNum); connect(ui->start, &QPushButton::clicked, this, [=](){ emit starting(10000); QThreadPool::globalInstance()->start(gen); }); connect(gen, &Generate::sendArray, bubble, &BubbleSort::recvArray); connect(gen, &Generate::sendArray, quick, &QuickSort::recvArray); connect(gen, &Generate::sendArray, this, [=](QVector<int> list){ QThreadPool::globalInstance()->start(bubble); QThreadPool::globalInstance()->start(quick); for(int i=0; i<list.size(); i++){ ui->randList->addItem(QString::number(list.at(i))); } }); connect(bubble, &BubbleSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->bubbleList->addItem(QString::number(list.at(i))); } }); connect(quick, &QuickSort::finish, this, [=](QVector<int> list){ for(int i=0; i<list.size(); i++){ ui->quickList->addItem(QString::number(list.at(i))); } }); }
|
子线程执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| Generate::Generate(QObject *parent) : QObject(parent), QRunnable() { setAutoDelete(true); }
void Generate::recvNum(int num) { m_num = num; }
void Generate::run() { qDebug()<<"生成随机数的线程的线程地址:"<<QThread::currentThread(); QVector<int> list; QElapsedTimer time; time.start(); for(int i=0; i<m_num; i++){ list.push_back(qrand()%100000); } int milsec = time.elapsed(); qDebug()<<"生成"<<m_num<<"个随机数总共用时:"<<milsec<<"毫秒"; emit sendArray(list); }
BubbleSort::BubbleSort(QObject *parent):QObject(parent), QRunnable() { setAutoDelete(true); }
void BubbleSort::recvArray(QVector<int> list) { m_list = list; }
void BubbleSort::run() { qDebug()<<"冒泡排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); int temp; for(int i=0; i<m_list.size()-1; i++){ for(int j=0; j<m_list.size()-i-1; j++){ if(m_list[j]>m_list[j+1]){ temp = m_list[j]; m_list[j] = m_list[j+1]; m_list[j+1] = temp; } } } int milsec = time.elapsed(); qDebug()<<"冒泡排序花费的时间是"<<milsec<<"毫秒"; emit finish(m_list); }
QuickSort::QuickSort(QObject *parent):QObject(parent), QRunnable() { setAutoDelete(true); }
void QuickSort::recvArray(QVector<int> list) { m_list = list; }
void QuickSort::run() { qDebug()<<"快速排序的线程的线程地址:"<<QThread::currentThread(); QElapsedTimer time; time.start(); quick(m_list,0,m_list.size()-1); int milsec = time.elapsed(); qDebug()<<"快速排序花费的时间是"<<milsec<<"毫秒"; emit finish(m_list); }
void QuickSort::quick(QVector<int>&list, int l, int r) { if(l<r){ int i=l, j=r; int x = list[i]; while(i<j){ while(i<j && list[j]>=x) j--; list[i]=list[j]; while(i<j && list[i]<=x) i++; list[j]=list[i]; } list[i] = x; quick(list,l,i-1); quick(list,i+1,r); } }
|
三、基于TCP的Qt网络通信
使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:
- QTcpServer:服务器类,用于监听客户端连接以及和客户端建立连接。
- QTcpSocket:通信的套接字类,客户端、服务器端都需要使用。
这两个套接字通信类都属于网络模块network
。
在Qt中不管调用读操作函数接收数据,还是调用写函数发送数据,操作的对象都是本地的由Qt框架维护的一块内存。因此,调用了发送函数数据不一定会马上被发送到网络中,调用了接收函数也不是直接从网络中接收数据,关于底层的相关操作是不需要使用者来维护的。
服务器端
通信流程:
- 创建套接字服务器QTcpServer对象
- 通过QTcpServer对象设置监听,即:QTcpServer::listen()
- 基于QTcpServer::newConnection()信号检测是否有新的客户端连接
- 如果有新的客户端连接调用QTcpSocket *QTcpServer::nextPendingConnection()得到通信的套接字对象
- 使用通信的套接字对象QTcpSocket和客户端进行通信
客户端
- 创建通信的套接字类QTcpSocket对象
- 使用服务器端绑定的IP和端口连接服务器QAbstractSocket::connectToHost()
- 使用QTcpSocket对象和服务器进行通信
案例1:通过服务端/客户端实现数据发送
服务端头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class MainWindow : public QMainWindow { Q_OBJECT
public: MainWindow(QWidget *parent = nullptr); ~MainWindow();
private slots: void on_setListen_clicked(); void on_sendMsg_clicked();
private: Ui::MainWindow *ui; QTcpServer* m_s; QTcpSocket* m_tcp; QLabel* m_status; };
|
服务端执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); ui->port->setText("8899"); setWindowTitle("服务器");
m_s = new QTcpServer(this);
connect(m_s, &QTcpServer::newConnection, this, [=](){ m_tcp = m_s->nextPendingConnection(); m_status->setPixmap(QPixmap(":/connect.png").scaled(20,20)); connect(m_tcp, &QTcpSocket::readyRead, this, [=](){ QByteArray data = m_tcp->readAll(); ui->record->append("客户端say:" + data); }); connect(m_tcp, &QTcpSocket::disconnected, this, [=](){ m_tcp->close(); m_tcp->deleteLater(); m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); }); });
m_status = new QLabel; m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); ui->statusbar->addWidget(new QLabel("连接状态:")); ui->statusbar->addWidget(m_status); }
MainWindow::~MainWindow() { delete ui; }
void MainWindow::on_setListen_clicked() { unsigned short port = ui->port->text().toUShort(); m_s->listen(QHostAddress::Any, port); ui->setListen->setDisabled(true); }
void MainWindow::on_sendMsg_clicked() { QString msg = ui->msg->toPlainText(); m_tcp->write(msg.toUtf8()); ui->record->append("服务器say:" + msg); ui->msg->clear(); }
|
客户端头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_sendMsg_clicked(); void on_connect_clicked(); void on_disconnect_clicked(); private: Ui::MainWindow *ui;
QTcpSocket* m_tcp; QLabel* m_status; };
|
客户端执行文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); ui->port->setText("8899"); ui->ip->setText("127.0.0.1"); setWindowTitle("客户端"); ui->disconnect->setDisabled(true);
m_tcp = new QTcpSocket(this);
connect(m_tcp, &QTcpSocket::readyRead, this, [=](){ QByteArray data = m_tcp->readAll(); ui->record->append("服务端say:" + data); });
connect(m_tcp, &QTcpSocket::disconnected, this, [=](){ m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); ui->record->append("服务端与客户端断开了连接....."); ui->connect->setDisabled(false); ui->disconnect->setEnabled(false); });
connect(m_tcp, &QTcpSocket::connected, this, [=](){ m_status->setPixmap(QPixmap(":/connect.png").scaled(20,20)); ui->record->append("已经成功连接到服务端....."); ui->connect->setDisabled(true); ui->disconnect->setEnabled(true); });
m_status = new QLabel; m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); ui->statusbar->addWidget(new QLabel("连接状态:")); ui->statusbar->addWidget(m_status); }
MainWindow::~MainWindow() { delete ui; }
void MainWindow::on_sendMsg_clicked() { QString msg = ui->msg->toPlainText(); m_tcp->write(msg.toUtf8()); ui->record->append("客户端say:" + msg); ui->msg->clear(); }
void MainWindow::on_connect_clicked() { QString ip = ui->ip->text(); unsigned short port = ui->port->text().toUShort(); m_tcp->connectToHost(QHostAddress(ip),port); }
void MainWindow::on_disconnect_clicked() { m_tcp->close(); ui->connect->setDisabled(false); ui->disconnect->setEnabled(false); }
|
案例2:通过服务端/客户端实现文件发送(C:\Qt\study\socket_Qt)
四、Json在Qt中使用
JSON(JavaScrip Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得JSON成为理想的数据交换语言,易于阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
可以理解为Json是一种数据格式,和语言无关,在什么语言中都可以使用Json,基于这种通用的数据格式,一般处理两方面任务:
- 组织数据(数据序列化),用于数据的网络传输
- 组数数据(数据序列化),写磁盘文件实现数据的持久化存储(一般以
.json
作为文件后缀)
Json中主要有两种数据格式:Json数组和Json对象,并且这两种格式可以交叉嵌套使用。
Json数组
Json数组使用[]表示,[]里面是元素,元素和元素之间使用逗号间隔,最后一个因素后边没有逗号,一个Json数组中支持同时存在多种不同类型的成员,包括:整型
、浮点
、字符串
、布尔类型
、json数组
、json对象
、空值(null)
。可见Json数组比起c/c++数组要灵活很多
Json对象
Json对象使用{}来描述,每个Json对象中可以存储若干个元素,每一个元素对应一个键值对(key:value结构),元素和元素之间使用逗号间隔,最后一个元素后边没有逗号,对于每个元素中的键值对有以下需要注意:
- 键值(key)必须是字符串,位于同一层级的键值不要重复(因为是通过键值取出对应的value值)
- value值的类型是可选的,,可根据实际需求指定,可用类型包括:
整型
、浮点
、字符串
、布尔类型
、json数组
、json对象
、空值(null)