文章目錄
- 1、QFile
- 1、打開
- 2、讀寫
- 3、關閉
- 4、程序
- 5、其它功能
- 2、多線程
- 1、演示
- 2、鎖
- 3、條件變量和信號量
1、QFile
Qt有自己的一套文件體系,不過Qt也可以使用C++,C,Linux的文件操作。使用Qt的文件體系和Qt自己的一些類型更好配合。
管理寫入讀取的就是Qt中的QIODevice類。QProcess相當于是對fork/exec操作進行的封裝;QTemporaryFile表示臨時文件,用完就銷毀,文件也就刪除;在寫大量數據時,要先創建一個臨時文件,將舊文件內容寫到臨時文件里,寫完后再刪除舊文件,這就是QSaveFile的操作。
// 這里的name用絕/相對路徑
QFile(const QString& name)// 查看文檔來查看打開、讀寫、關閉文件操作接口
1、打開
不過實際用的是這個,它可以直接拿到之前設置的路徑
關于OpenMode
2、讀寫
QByteArray容易轉QString。
3、關閉
關閉時就是在釋放文件描述符表中的表項,文件描述符表存在上限。
4、程序
// mainwindow.h#include <QMainWindow>
#include <QPlainTextEdit>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void handle1();void handle2();private:Ui::MainWindow *ui;QPlainTextEdit* edit;
};// mainwindow.cpp#include <QDebug>
#include <QFileDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);this->setWindowTitle("窗口");QMenuBar* menuBar = this->menuBar();QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);// 形成菜單QAction* action1 = new QAction("打開");QAction* action2 = new QAction("保存");menu->addAction(action1);menu->addAction(action2);// 指定輸入框edit = new QPlainTextEdit();QFont font;font.setPixelSize(20);edit->setFont(font);this->setCentralWidget(edit);connect(action1, &QAction::triggered, this, &MainWindow::handle1);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle1()
{// 彈出打開文件對話框QString path = QFileDialog::getOpenFileName(this);// 文件名顯示到狀態欄QStatusBar* statusBar = this->statusBar();statusBar->showMessage(path);// 通過路徑構造QFile對象QFile file(path);bool ret = file.open(QIODevice::ReadOnly);if (!ret){statusBar->showMessage(path + " 打開失敗!");return ;}// 讀取文件// 即使返回值是QByteArray, 也可以直接用QString接收// 但前提必須不是二進制文件, 是文本文件QString text = file.readAll();file.close();// 讀到的內容設置到輸入框中edit->setPlainText(text);
}void MainWindow::handle2()
{QString path = QFileDialog::getSaveFileName(this);QStatusBar* statusBar = this->statusBar();statusBar->showMessage(path);QFile file(path);bool ret = file.open(QFile::WriteOnly);if (!ret){statusBar->showMessage(path + " 打開失敗!");return ;}const QString& text = edit->toPlainText();// 轉成QByteArrayfile.write(text.toUtf8());file.close();
}
5、其它功能
QFileInfo可以獲取到Qt的文件的相關屬性。
void Widget::on_pushButton_clicked()
{QString path = QFileDialog::getOpenFileName(this);QFileInfo fileInfo(path); // 構造QFileInfo對象qDebug() << fileInfo.fileName();qDebug() << fileInfo.suffix();
}
2、多線程
和Linux的多線程本質是一樣的。Linux有pthread庫,C++11有std::thread,Qt也封裝了線程庫,參考了Java的線程庫。
創建線程要創建QThread對象,并創建一個QThread的子類,重寫父類的run函數來作為線程的入口函數。
start就是調用系統API來創建線程,創建好后自動執行run函數。
1、演示
創建QWidget項目,通過線程完成定時器功能。
將intValue屬性改為10。
創建新的子類
// thread.h#include <QWidget>
#include <QThread>class Thread : public QThread
{Q_OBJECT
public:Thread();void run();signals:void notify();
};// widget.h#include <QWidget>
#include "thread.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handle();private:Ui::Widget *ui;Thread thread;
};// thread.cpp#include "thread.h"Thread::Thread()
{}void Thread::run()
{// 由于Qt的線程策略, 不允許多個線程同時修改界面// run實現計時效果// 每過一秒鐘, 通過信號槽通知主線程修改界面for(int i = 0; i < 10; ++i){sleep(1);emit notify();}
}// widget.cpp#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(&thread, &Thread::notify, this, &Widget::handle);thread.start();
}void Widget::handle()
{int value = ui->lcdNumber->intValue();--value;ui->lcdNumber->display(value);
}
2、鎖
Qt的鎖是QMutex,lock和unlock方法。
QWidget項目,創建繼承QThread的類Thread。
// thread.h#include <QWidget>
#include <QThread>class Thread : public QThread
{Q_OBJECT
public:Thread();// 聲明static int num;void run();
};// thread.cpp#include "thread.h"// 定義
int Thread::num = 0;Thread::Thread()
{}void Thread::run()
{for(int i = 0; i < 47000; ++i){++num;}
}// widget.cpp#include <QDebug>
// widget.h中引入thread.hWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);Thread t1;Thread t2;t1.start();t2.start();// 線程等待// 如果不等待, 那么除了這兩個, Widget這個主線程還在并發執行// t1t2開始了, 但是Widget不停, 那么很快就執行到了打印, 此時結果肯定不大t1.wait();t2.wait();qDebug() << Thread::num;
}
這樣肯定不會打印出47000 * 2的數字。
加鎖
// thread.h#include <QMutex>public:// 聲明static int num;static QMutex mutex;// thread.cpp// 定義
int Thread::num = 0;
QMutex Thread::mutex;void Thread::run()
{for(int i = 0; i < 47000; ++i){mutex.lock();++num;mutex.unlock();}
}
Qt中的智能指針是QMutexLocker,C++ 11中則是std::lock_guard。
// thread.cpp#include "thread.h"
#include <QMutexLocker>// 定義
int Thread::num = 0;
QMutex Thread::mutex;void Thread::run()
{for(int i = 0; i < 47000; ++i){QMutexLocker locker(&mutex);++num;}
}
Qt還有別的鎖
3、條件變量和信號量
QWaitCondition條件變量類,有wait,wake,wakeAll方法
例子
QMutex mutex;
QWaitCondition condition;//在等待線程中
mutex.lock();//檢查條件是否滿足, 若不滿足則等待
while (!conditionFullfilled())
{condition.wait(&mutex); //等待條件滿足并釋放鎖
}//條件滿足后繼續執行
//...
mutex.unlock();//在改變條件的線程中
mutex.lock();//改變條件
changeCondition();
condition.wakeAll(); //喚醒等待的線程
mutex.unlock();
QSemaphore信號量類
QSemaphore semaphore(2); //同時允許兩個線程訪問共享資源//在需要訪問共享資源的線程中
semaphore.acquire(); //嘗試獲取信號量,若已滿則阻塞//訪問共享資源
//...
semaphore.release(); //釋放信號量//在另?個線程中進行類似操作
結束。