Qt作为一种跨平台开发工具,具有强大的基本数据类型基础,除了承袭C++和STL数据类型的衣钵,还抽象出大量的Qt特色数据类型支撑以满足应用开发的各种需求。本文记录了常用的一些数据类型,持续更新。

Qt基本数据类型

以下数据类型对应不同位数,用于要求较高的场合;跨平台环境应该避免直接使用int和longint最常见是32位的,但是也见16位64位long32位系统是32位,相当于int,在64位系统是64位的,相当于long long。

类型 大小 说明
bool 8位 布尔
int8_t/qint8 8位 signed char
int16_t/qint16 16位 signed short
int32_t/qint32/int 32位 signed int
int64_t/qint64 64位 long long int
uint8_t/quint8 8位 unsigned char
uint16_t/quint16 16位 unsigned short
uint32_t/quint32 32位 unsigned int
uint64_t/quint64 64位 unsigned long long int
float 16位 浮点数
double 32位 浮点数
const char* 32位 指向字符串常量的指针

QString类型

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
////增加字符
//append(QString str);
//operator+=;
//insert(int pos,QString str);
QString str1 = "Hello";
str1 += "World"; //str1 = HelloWorld;
str1.append("World"); //str1 = HelloWorldWorld
str1.insert(3,QString str2); //在str1下标3前面插入字符str2

//删除字符
//remove(int pos,int n); //从pos位置开始删除n个字符;
str1.remove(0,5);

//修改
//operator= //赋值替代
//sprintf("%s...",...); //打印替代
//replace(int pos,int n,QString str); //将pos下标后的n个字符替换成str
str1.sprintf("%s %s %s","Hello","world","Eden"); //组合打印,str1="Hello world Eden";
str1.replace(6,3,"OhMyGod");//str1下标6及其后三个字符替换,如果6+3越界会自动调整至末尾


//查询
//int indexOf(QString str,int pos,Qt::CaseSensitive); //从下标pos开始查找str,返回第一个匹配下班,默认CaseSensitive大小写敏感
//int lastIndexOf(QString str,int pos,Qt::CaseSensitive) //反向查找,返回最后一个匹配下标
str1.indexOf("Hello");

//其他
//clear() //清空
//isEmpty() //是否空字符串("")
//isNull() //是否空对象
//reserve(int n) //类似vector
//resize(int n)
//length()/size()

//子串
left(n); //从左到右截取n个字符
right(n); //从右到左截取n个字符
mid(0,n); //左闭右开,从0开始截取n个字符
mid(pos) //截取pos到末尾

//去除path的前后空格
QString tmp = path.trimmed();

//数字转字符串
QString str4;
str.setNum(64); //64->"64"
//字符串转其他数据类型
str.toInt()
str.toDouble()
......

//开头插入
QString str3 = "shop";
str3.prepend("Photo"); //str3 = "Photoshop";

参数格式化打印

1
2
3
4
5
QString test("Info:");
int age = 16;
QString name = "Eden";
test += QString("age=%1 name=%2").arg(QString:: number(age), name);
qDebug() << test; //"Info:age=16 name=Eden"

QStringList方法

类似vector<string>,Qt有容器类型QVector<QString>,但针对字符串数组Qt抽象出了一种类QStringList,并且提供了额外的操作接口,方便使用。

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
QStringList list1 = {"apple", "banana", "cherry"};

//增加
//operator<<
//append(QString str);
QStringList Person;
Person<<"Eden"<<"Mike"<<"Lucy";
Person.append("Mary");

//删除元素
//removeOne(QString str); //删除第一个匹配str的字符串
//removeAt(int pos); //删除下标pos的字符串

//遍历元素
qDebug()<<Person; //支持输出整个列表,("Eden", "Mike", "Lucy")
for(int i=0; i<Person.length(); i++){
qDebug()<<Person[i]; //逐个遍历
}

// 插入元素
//insert(int pos,QString str); //在pos前插入字符串str
ls1.insert(1,"God");

//查找基本同QString
//int indexOf(QString str,int pos,Qt::CaseSensitive); //从下标pos开始查找str,返回第一个匹配下班,默认CaseSensitive大小写敏感
//int lastIndexOf(QString str,int pos,Qt::CaseSensitive) //反向查找,返回最后一个匹配下标

QSettings写ini文件

ini文件是一种配置文件,当Qt需要与配置交互时,可以使用QSettings进行读写;一个ini配置文件的结构如下,因为ini文件可能是整个项目共享的,因此需要使用Section作为分组(分节)写入和读取,配置项就是简单的键值对

1
2
3
4
5
6
[Section]
key = value

//实例:
[Person]
Eden=18

写操作

1
2
3
4
5
QSettings setting("D:\\Documents\\Desktop\\note\\test.ini",QSettings::IniFormat); //路径,ini配置

setting.beginGroup("Person"); //组
setting.setValue("Eden",18); //键、值
setting.endGroup(); //结束组

读操作:通过键查询值

1
2
3
4
5
QSettings rsetting("D:\\Documents\\Desktop\\note\\test.ini",QSettings::IniFormat); //路径,ini配置
rsetting.beginGroup("Person"); //组
int num = rsetting.value("Eden").toInt(); //读取的是QVariant,需要转换
rsetting.endGroup();
qDebug()<<num;

除了ini格式,QSetting还支持NativeFormat格式,用于读取windows注册表(没用过,鸽掉

遍历读取ini文件

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
QSettings setting("D:\\Documents\\Desktop\\note\\test.ini",QSettings::IniFormat);

setting.clear(); //清除文件内容
setting.sync(); //同步

setting.beginGroup("Master");
setting.setValue("GesiLa",12);
setting.setValue("KING Kong",100);
setting.endGroup();

setting.beginGroup("Superman");
setting.setValue("Dijia","good");
setting.setValue("GaiYa","commom");
setting.endGroup();

setting.sync(); //同步写入新设置

/*********** 写入文件形如:
* [Master]
GesiLa=12
KING%20Kong=100

[Superman]
Dijia=good
GaiYa=commom
* **********/

//遍历读取
QStringList groups = setting.childGroups();
for(QString& pos:groups){ //得到Section名称:怪兽、超人
setting.beginGroup(pos);
QStringList keys = setting.allKeys(); //遍历每个section的key
for(QString kpos:keys){
qDebug()<<setting.value(kpos).toString();//统一按字符串读出
}
setting.endGroup();
}

QDir、QFile文件操作相关

以下涉及新建目录创建文本文件写入文本复制文件重命名文件删除文件删除目录等;

一个值得重视的点是:当使用QFile::copy(path)或者QFile::remove(path)时,如果path是相对路径,那么是相对Qt工作路径的QDir::currentPath(),当编译文件夹目的文件夹不一致时就会导致错误路径操作。

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
    QString curDir = QDir::currentPath(); //获取Qt当前工作目录
qDebug()<<curDir;

QDir dir("D:/Documents/Desktop/note"); //dir目录
qDebug()<<dir.path(); //获取QDir对象路径
if(!dir.exists("QDir_test")){ //dir目录下新建目录
if(dir.mkdir("D:/Documents/Desktop/note/QDir_test")) //QDir新建文件夹
qDebug()<<"mkdir Done";
}
else
qDebug()<<"Dir exists";

dir.cd("QDir_test"); //更新QDir,cd会将字符追加到QDir
qDebug()<<dir.path();

QFile new_file(dir.filePath("newfile.txt")); //QFile绑定QDir下的文件

if(new_file.open(QIODevice::ReadWrite|QIODevice::Text)){ //打开才真正创建
QTextStream out(&new_file); //文本流
out<<"Hello World1";
new_file.close();
}

//复制文件newfile.txt到copyfile.txt,且重命名newfile.txt为sourcefile.txt
for(QString& file_name:dir.entryList(QDir::Files)){ //仅遍历文件
if(file_name=="newfile.txt"){
QString et_name = dir.path()+"/"+file_name;
qDebug()<<et_name;
QFile::copy(et_name,dir.path()+"/"+"copyfile.txt"); //复制
new_file.rename("sourcefile.txt");
}
}

dir.mkdir("new_dir");
for(QString& file_name:dir.entryList(QDir::Files|QDir::Dirs)){ //还可以打印子目录
qDebug()<<file_name;
}

//析构步骤,运行上述代码检查是否创建文件成功,最后再运行以下代码:
#if finished
dir.rmdir("new_dir");
for(QString& file_name:dir.entryList(QDir::Files)){ //删除文件
QFile::remove(dir.path()+"/"+file_name);
}

dir.cd(".."); //返回上层目录
qDebug()<<dir;
dir.rmdir("QDir_test"); //删除父目录
#end if

entryList获取文件与目录

1
2
3
//获取所有文件和目录(AllEntries),不包括本目录和上级目录(NoDotAndDotDot),包括隐藏文件和目录(Hidden)
QStringList fileNames = directory.entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
QStringList fileNames =directory.entryList(QDir::Files); //仅文件,QDir::Dirs仅目录

QDir斜杠、反斜杠转换

1
2
3
4
5
//将 '\' 转为 '/'(windows to linux)
strFilePath=QDir::fromNativeSeparators(strFilePath);

//将 '/' 转为 '\'(linux to windows)
strFilePath=QDir::toNativeSeparators(strFilePath);

QDir::entryInfoList

如果需要遍历目录下文件、目录、软链接及其路径信息,可以考虑使用QDir::entryInfoList,具体是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
QFileInfoList QDir::entryInfoList(
const QStringList &nameFilters = QStringList(),
QDir::Filters filters = QDir::NoFilter,
QDir::SortFlags sort = QDir::NoSort) const

其中:
nameFilters:QStringList对象,表明文件通配符(不是正则表达式),如:
- "*.txt": 匹配所有 .txt 文件
- "doc?.pdf": 匹配如 doc1.pdf, docA.pdf 等
- "[abc].txt": 匹配 a.txt, b.txt, c.txt
- "file[!0-9].dat": 匹配不以数字结尾的 file.dat 文件

filters:文件类型筛选,常用如:
- QDir::Files: 列出文件
- QDir::Dirs: 列出目录
- QDir::NoDotAndDotDot: 不包括 "."".." 目录
- QDir::AllEntries: 列出所有条目(文件和目录)

sort:排序规则,如
- QDir::Name: 按名称A到Z排序
- QDir::Time: 按时间早到晚排序
- QDir::Size: 按大小小到大排序
- QDir::Type: 按类型A到Z排序
若需要排序颠倒,则QDir::Time | QDir::Reversed
其返回的是一个QFileInfoList对象,即QFileInfo类型的列表,详见后文;

示例:

1
2
3
4
5
QDir dir("D:\\Documents\\Desktop\\logtest");
QFileInfoList finfoList = dir.entryInfoList(QStringList() << "*.log"<<"*.exe", QDir::Files, QDir::Time);
for (QFileInfo& pos : finfoList) {
qDebug() << pos.absoluteFilePath();
}

QFileInfo

类型判断

常用三种文件类型判断,普通文件目录文件软链接文件

1
2
3
isFile();
isDir();
isSymLink();

Windows软链接与Unix软链接

软链接,又称符号链接;在Unix中(Linux、IOS、macOS)中,软链接指向是真实的文件打开软链接就是打开对应的文件/目录

1
2
3
4
5
6
7
#ifdef Q_OS_UNIX
QFileInfo info1("/home/bob/bin/untabify"); //创建软链接,链接到/opt/pretty++/bin/untabify
info1.isSymLink(); // 是否软链接,returns true
info1.absoluteFilePath(); // 绝对路径,returns "/home/bob/bin/untabify"
info1.size(); // 软链接大小,returns 56201,同/opt/pretty++/bin/untabify大小
info1.symLinkTarget(); // 真实链接:returns "/opt/pretty++/bin/untabify"
#endif
Windows中(NTFS文件系统),lnk即一般快捷方式被视为软链接,在Unix中软链接一般只存储目标路径,而lnk存储路径图标等目标元数据信息,其本身就是一个实体,并不是真正意义上的软链接。
1
2
3
4
5
6
7
#ifdef Q_OS_WIN
QFileInfo info1("C:\\Documents and Settings\\Bob\\untabify.lnk"); //lnk文件
info1.isSymLink(); // 是否软链接,Qt认为lnk属于软链接,returns true
info1.absoluteFilePath(); // returns "C:/Documents and Settings/Bob/untabify.lnk"
info1.size(); // returns 743,这里大小就是lnk本身大小,并不指向真实大小
info1.symLinkTarget(); // 真实链接:returns "C:/Pretty++/untabify"
#endif

QFileInfo文件名/路径名取法

摘自QFileInfo主要函数详解

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
//相对路径文件:
============================relative file path============================
=================QFileInfo("./user/xueying/script.tag.gz")================
baseName--------------------->>> "script",无后缀文件名
completeBaseName------------->>> "script.tag",带一个后缀文件名
suffix----------------------->>> "gz",最后一个后缀
completeSuffix--------------->>> "tag.gz",完整后缀
path------------------------->>> "./user/xueying",最后一级目录(自行补充分隔符)
filePath--------------------->>> "./user/xueying/script.tag.gz",绝对路径/相对路径
fileName--------------------->>> "script.tag.gz",完整文件名,若为目录为空字符
absolutePath----------------->>> "E:/project/qt/fileinfoTest/bin/user/xueying",绝对路径(自行补充分隔符)
absoluteFilePath------------->>> "E:/project/qt/fileinfoTest/bin/user/xueying/script.tag.gz",绝对路径+完整文件名
absoluteDir().dirName-------->>> "xueying",最后一级目录名称
absoluteDir().absolutePath--->>> "E:/project/qt/fileinfoTest/bin/user/xueying",最后一级目录完整绝对路径(自行补充分隔符)
absoluteDir().path----------->>> "E:/project/qt/fileinfoTest/bin/user/xueying",最后一级目录完整绝对路径(自行补充分隔符)
dir().dirName---------------->>> "xueying",最后一级目录名称
dir().absolutePath----------->>> "E:/project/qt/fileinfoTest/bin/user/xueying",最后一级目录完整绝对路径(自行补充分隔符)
dir().path------------------->>> "./user/xueying",最后一级目录相对路径(自行补充分隔符)

//绝对路径文件基本同上;

//带末尾分隔符的相对路径目录:
=====================relative dir path with QDir::sepator()=====================
==========================QFileInfo("./user/xueying/")==========================
baseName--------------------->>> ""
completeBaseName------------->>> ""
suffix----------------------->>> ""
completeSuffix--------------->>> ""
bundleName------------------->>> ""
path------------------------->>> "./user/xueying",最后一级目录,(自行补充分隔符)
filePath--------------------->>> "./user/xueying/",当前目录路径,(按需补充分隔符)
fileName--------------------->>> ""
absolutePath----------------->>> "E:/project/qt/fileinfoTest/bin/user",当前目录所在的目录绝对路径(上一级目录)(自行补充分隔符)
absoluteFilePath------------->>> "E:/project/qt/fileinfoTest/bin/user/xueying",当前目录绝对路径(自行补充分隔符)
absoluteDir().dirName-------->>> "user"
absoluteDir().absolutePath--->>> "E:/project/qt/fileinfoTest/bin/user"
absoluteDir().path----------->>> "E:/project/qt/fileinfoTest/bin/user"
dir().dirName---------------->>> "xueying"
dir().absolutePath----------->>> "E:/project/qt/fileinfoTest/bin/user/xueying"
dir().path------------------->>> "./user/xueying"

//不带末尾分隔符的相对路径目录:
======================relative dir path no QDir::sepator()======================
============================QFileInfo("./user/xueying")=========================
baseName--------------------->>> "xueying",(1. baseName不为空)
completeBaseName------------->>> "xueying" (1. baseName不为空)
suffix----------------------->>> ""
completeSuffix--------------->>> ""
path------------------------->>> "./user" (2.path截取带末尾分隔符的目录)
filePath--------------------->>> "./user/xueying" (3.filePath有无分隔符取决于原来有没有分隔符)
fileName--------------------->>> "xueying" (4. fileName不为空)
absolutePath----------------->>> "E:/project/qt/fileinfoTest/bin/user"
absoluteFilePath------------->>> "E:/project/qt/fileinfoTest/bin/user/xueying"
absoluteDir().dirName-------->>> "user"
absoluteDir().absolutePath--->>> "E:/project/qt/fileinfoTest/bin/user"
absoluteDir().path----------->>> "E:/project/qt/fileinfoTest/bin/user"
dir().dirName---------------->>> "user"(5. 目录名,以后面是否有斜杠为准,不是xueying)
dir().absolutePath----------->>> "E:/project/qt/fileinfoTest/bin/user"(5. 目录名,以后面是否有斜杠为准,不是xueying)
dir().path------------------->>> "./user" (5. 目录名,以后面是否有斜杠为准,不是xueying)

//绝对路径目录基本同理。

跨平台路径末尾自适应加分隔符,windows Qt下添加"\",linux Qt下添加"/"

1
2
3
QString srcPath("/usr/root");
if (!srcPath.endsWith(QDir::separator()))
srcPath += QDir::separator(); //末尾加分隔符,"/usr/root/"

QVariant容器

Qt需要进行大量的数据传递,指定一种返回类型可能不能满足数据的传输要求,因此Qt引入QVariant支持各种数据类型;QVariant支持几乎所有的Qt数据类型以及C++基本数据类型,也支持符合要求的自定义类型

QVariant构造基本数据类型

对于QVariant支持的数据类型,可以直接构造并且赋值读取时转换为对应类型,也可以使用setValue函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
QVariant num(123);
int inum = num.toInt();
qDebug()<<inum;

QString qstr("Hello World");
QVariant str = qstr;
QString str1 = str.toString();
qDebug()<<str1;

QVariant v;
v.setValue(42); // 设置为整数
v.setValue(QString("Hello")); // 设置为字符串
v.setValue(QColor(Qt::red)); // 设置为颜色

isValid()返回true代表初始化类型有效,绑定了某种数据类型对象;isNull类似的,可以检验对象是否存在;

1
2
3
4
5
6
7
8
QVariant test;
qDebug()<<test.isValid(); //false,无绑定
qDebug()<<test.isNull(); //true,Null对象

QVariant test1("");
qDebug()<<test1.type(); //QVariant::QString
qDebug()<<test1.isValid(); //true,绑定QVariant::QString
qDebug()<<test1.isNull(); //false,空字符不为Null

自定义数据类型与fromValue()

fromValue()setValue()功能一致,都是QVariant类型赋值,但用法上略有区别;setValue()QVariant的一个成员函数,为已存在的QVariant对象赋值,而fromValue()是一个类静态函数,能够在构造的同时完成赋值,并且返回一个新的QVriant对象,支持更广泛的数据类型,尤其是自定义数据类型。此外,Qt数据类型都在元对象系统中定义,自定义的数据类型需要在定义的结构体/类下方使用宏Q_DECLARE_METATYPE声明;

读取时,使用QVariant::value函数可读出指定数据类型数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//头文件定义新数据类型
struct Person{
int id;
QString name;
};
Q_DECLARE_METATYPE(Person)

//cpp文件:
Person person;
person.id = 10;
person.name = "Eden"; //person类实例

QVariant test = QVariant::fromValue(person); //person类型转换到QVariant类型

//从QVariant读取自定义的person类型
if(!test.canConvert<Person>()) //先判断是否可转换
qFatal("Convert illegal!!");
Person rperson = test.value<Person>();
qDebug()<<rperson.id;
qDebug()<<rperson.name;

QList & QVariantList

QList是Qt最常用的容器,是一种双向链表结构,仅列出常见接口:

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
QList<QString> lst;
lst<<"elem1"<<"elem2"<<"elem3";
qDebug()<<lst; //("elem1", "elem2", "elem3")

lst.append("elem4"); //尾插,push_back亦可
lst.prepend("elem0"); //头插,push_front亦可
qDebug()<<lst; //("elem0", "elem1", "elem2", "elem3", "elem4")

lst.replace(4,"elem4_rp"); //替换
qDebug()<<lst; //("elem0", "elem1", "elem2", "elem3", "elem4_rp")

QString elem = lst.takeAt(0); //删除并返回下标0
qDebug()<<elem; //"elem0"
qDebug()<<lst; //("elem1", "elem2", "elem3", "elem4_rp")

lst.swap(0,3); //交换
qDebug()<<lst; //("elem4_rp", "elem2", "elem3", "elem1");

lst.insert(0,"elem0"); //指定位置前插入
qDebug()<<lst; //("elem0", "elem4_rp", "elem2", "elem3", "elem1")

lst.removeAt(2); //删除下标2
lst.removeFirst(); //首个字符,同pop_front()
lst.removeLast(); //最后字符,同pop_back()
lst.removeOne("elem0"); //删除第一个匹配项
lst.removeAll(); //同clear()

back() //尾元素
front() //第一个元素;

  • QVariantListQList<QVariant>的别名类型。

QMap、QHash & QVariantMap、QVariantHash & QMultiHash

Qt的STL延续了C++ STL的大部分特性,但是有一些地方用法却不一样;

QMap对应C++的map结构,都是有序的,QHash对应unordered_map,是高效的哈希表查找结构,是无序的,区别以下(不完全):

  1. QMapQHash支持value函数,用于索引某个键的值,而mapunordered_map只能使用find(key)的方式索引迭代器。

  2. QMapQHash插入相同的键不会返回pair迭代器检查是否失败,而是会覆盖相同键的值

  3. QMapQHash插入支持相同的键,使用成员函数QMap/QHash.insertMulti(key,value)能够强制插入相同的key

  4. 遍历不能直接使用for(auto pos:QMap),这里返回的pos不是QMap/QHash的迭代器,而是int类型指向存储的值,因此宜使用普通迭代器方法for(auto i=.begin();i!=.end(); i++)

  5. map/unordered_map的迭代器使用pos.firstpos.second访问键值,QMap/QHash迭代器使用pos.key()pos.value()访问键值。

  • QVariantMapQVariantHash分别是QMap<QString, QVariant>QHash<QString, QVariant>的别名;

  • QMultiHash对应multimapinsert函数支持多个相同键的插入。

value(x,x)

QMap.value(x,x),返回x对应的值,如果键x不存在,返回值为x;

QByteArray

QByteArray字节数组,类似char[]或者char*,不同于QString使用UTF-16表示数据(两字节/四字节),每个字符元素是2字节QByteArray每个字符是8位数据,即0-255,既可以表示128个ASCII码字符,也可以表示原始的字节格式,采用UTF-8编码方式,对char兼容较好,但不直接支持Unicode

QByteArray常用接口函数

1
2
3
const char* str = "Hello World";
QByteArray byteArray1(str,-1); //-1可缺省,表示自动计算str长度
QByteArray byteArray2(3,'w'); //www

插入append/push_backprepend/push_frontinsert等能够插入字符/字符串,用法同QList,但QByteArray没有pop接口删除相关方法

1
2
3
4
5
byteArray1.remove(0,5); //删除0及其后5个字符
byteArray1.chop(2); //删除尾部2个字节
byteArray1.truncate(2); //仅保留2下标前部分,后面丢弃
clear //清空

替换字符使用operator[]at(i)只用于遍历读取场合,不可用于写操作byteArray1.at(0) = '1'非法的。

查找相关接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
indexOf(char) //同QString
indexOf(char[]) //同QString
lastIndexOf(char) //同QString
lastIndexOf(char[]) //同QString
left(num) //同QString
right(num) //同QString
mid(pos,num) //同QString

//统计字符/字符串
count('x')
count("xx")
contains("xx")
startsWith("xx")
endsWith("xx")

QString、QByteArray、std::string、char*转换

ASCII8位数据,对应128个早期定义的英文/数字/控制字符UniCode是为了在全世界建立统一的字符集,约定了每个字符唯一的二进制编码,前128个码仍然沿用ASCII码;

然而UniCode只约定了二进制编码表示,没有具体约束存储方式,UTF-8使用1字节——3字节存储字符,此外还有UTF-16、32等少用的字符集。

而在QString中,每个符号是一个QChar,QChar使用UTF-16进行编码,而stringQByteArraychar[]内部均使用8位存储一个字符;

以下将QString按本地八位编码存储转换,使用fromHex进行16进制解析,因此byteArray的第一个16位数字:31被解析成0x49,进而对应数字1的ASCII,hexbyteArray[0] = '1',后面的解析同理;

1
2
3
QString test("31323334");
QByteArray byteArray = test.toLocal8Bit();//转换到QByteArray,8位存储一个字符,如byteArray[0] = '3';
QByteArray hexbyteArray = QByteArray::fromHex(byteArray); //十六进制转换,输出1234

在单字节存储中,Latin1UTF-8是常用的两种编码,也是MySql的两种常用编码;其中Latin1是严格的单字节存储,就像ASCII一样,但是ASCII的最高一位实际上是奇偶校验,而Latin1实实在在可以表示256种字符,除了兼容ASCII的128种,还支持另外一些控制字符与拉丁字符;

因此,ASCII码和Latin1都不具备表示所有字符的能力:

1
2
3
QString test("你");
QByteArray byteArray1 = test.toUtf8(); //"\xEF\xBF\xBD\xEF\xBF\xBD"
QByteArray byteArray2 = test.toLatin1(); //"??"
对中文字符处理时,应该对编码转换谨慎处理;

Qt除了兼容QString、QByteArray,支持std、传统的一些字符串类型转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
QString.toStdString() //QString转std::string
QString::fromStdString(std::string) //std::string转QString

//QString转QByteArray
QByteArray = QString.toUtf8()
QByteArray = QString.toLatin1()
QByteArray = QString.toLocal8Bit()

//const char*/QByteArray转QString
QString = QString::fromUtf8(QByteArray/const char*)
QString = QString::fromLatin1(QByteArray/const char*)
QString = QString::fromLocal8Bit(QByteArray/const char*)

//QByteArray转const char*
const char* arry = QByteArray.data();

//string转char[],主要是兼容旧方法,例如system函数参数列表应该使用C风格字符串
string.c_str();

QJson

记录了Qt的Json封装和解析,包括QJsonDocument、QJsonObject、QJsonValue、QJsonArray类型:

一个示例json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"Company": "Digia",
"From": "1991",
"Name": "Qt",
"Page": {
"Developers": "https://www.qt.io/developers/",
"Download": "https://www.qt.io/download/",
"Home": "https://www.qt.io/"
},
"Version": [
4.8,
5.2,
5.7
]
}

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
//封装出Json:
QJsonObject allJson; //一级键值
allJson.insert("Company","Digia");
allJson.insert("From","1991");
allJson.insert("Name","Qt");

QJsonObject pageJson; //插入二级键值
pageJson.insert("Developers","https://www.qt.io/developers/");
pageJson.insert("Download","https://www.qt.io/download/");
pageJson.insert("Home","https://www.qt.io/");

QJsonArray versionJson; //插值
versionJson.append(4.8);
versionJson.append(5.2);
versionJson.append(5.7);

allJson.insert("Page",pageJson); //二级键值
allJson.insert("Version",versionJson);

qDebug()<<allJson;

QJsonDocument doc(allJson);

QByteArray byteArray = doc.toJson(QJsonDocument::Indented); //Indented保留缩进、空格,易读;Compact则去除,高效;
//QString str(byteArray);

QDir dir("D:/Documents/Desktop/note");
QFile jsonFile(dir.filePath("test.json"));

if(jsonFile.open(QIODevice::WriteOnly|QIODevice::Text)){ //写入本地
jsonFile.write(byteArray);
jsonFile.close();
}

//解析示例Json:
QFile rJsonFile(dir.filePath("test.json"));
QByteArray rbyteArray;
if(rJsonFile.open(QIODevice::ReadOnly|QIODevice::Text)){
rbyteArray = rJsonFile.readAll();
rJsonFile.close();
}
if(rbyteArray.isEmpty())
qFatal("read error!!");

QJsonParseError jsonError;
QJsonDocument rdoc = QJsonDocument::fromJson(rbyteArray,&jsonError);
if(!rdoc.isNull()&&jsonError.error==QJsonParseError::NoError){
QJsonObject rallJson =rdoc.object();
QJsonValue cpnyValue = rallJson.value("Company");
qDebug()<<"Company:"<<cpnyValue.toString();

QJsonValue fromValue = rallJson.value("From");
qDebug()<<"From:"<<fromValue.toString();

QJsonObject PaegValue = rallJson.value("Page").toObject();
QJsonValue deveValye = PaegValue.value("Developers");
qDebug()<<"Developers:"<<deveValye.toString();
//...

QJsonValue versionValue = rallJson.value("Version");
QJsonArray versionArray = versionValue.toArray();
qDebug()<<"Version:";
for(int i=0; i<versionArray.size(); i++){
qDebug()<<versionArray[i].toDouble();
}
}
qDebug()<<"Done";

QTextStream

Qt除了使用Write读写文件,还支持文本流读写文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
QFile file("D:\\Documents\\Desktop\\note\\fileTest.log");
if(file.open(QIODevice::WriteOnly|QIODevice::Text)){ //写
QTextStream stream(&file); //绑定对象法一
stream << "Hello World!!";
file.close();
}
//读
if(file.open(QIODevice::ReadOnly|QIODevice::Text)){
QTextStream rstream;
rstream.setDevice(&file); //绑定对象法二
QString output = rstream.readAll();
qDebug()<<output;
file.close();
}

Qt正则匹配

Qt 5以上可使用QRegularExpression:

  1. 判断并捕获匹配字段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    QString test = "Eden,23 years old";
    QRegularExpression re("^([a-z]*),(\\d+)", QRegularExpression::CaseInsensitiveOption); //忽略大小写
    QRegularExpressionMatch match = re.match(test);
    if (match.hasMatch()) {
    QString name = match.captured(1); //Eden
    int age = match.captured(2).toInt(); //23
    qDebug() << name;
    qDebug() << age;
    }

  2. 连续匹配

    1
    2
    3
    4
    5
    6
    7
    8
    QString test = "Eden 20;Mike 30;Lucy 40;";
    QRegularExpression re("(\\d{2})"); //查找2位数字
    QRegularExpressionMatchIterator match = re.globalMatch(test); //匹配
    while (match.hasNext()) { //连续匹配
    QRegularExpressionMatch pos = match.next();
    int age = pos.captured(0).toInt();
    qDebug() << age; //20 30 40
    }

  3. 匹配替换字符

    1
    2
    3
    4
    QString test = "I am Superman";
    QRegularExpression re("\\s([a-z]+)$",QRegularExpression::CaseInsensitiveOption); //忽略大小写,匹配Superman
    QString rtest = test.replace(re, " Master"); //替换匹配字段
    qDebug() << rtest; //"I am Master"

QProcess

用于新建一个进程,且调用相应exe并获取返回结果;

这里先编译一个text.exe供给调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int calculation(int a,int b){
return a+b;
}

int main(int argc,const char* argv[]){
if (argc!=3){
cout<<"Wrong parameter!!"<<endl;
return -1;
}
cout<<"Your Result is:"<<calculation(stoi(argv[1]),stoi(argv[2]))<<endl;
return 0;
}

在Qt中调用并读取返回结果:

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
QProcess process;
QString exePath("D:/Documents/Desktop/test/test.exe");
QStringList qslParam;
qslParam << "10" << "20"; //参数列表
process.start(exePath, qslParam);
//或者:
//process.setProgram(exePath);
//process.setArguments(qslParam);
//process.start();

if (!process.waitForStarted()) {
qWarning() << "start error";
}

if (!process.waitForFinished()) {
qWarning() << "handle error";
}

QString output = QString::fromUtf8(process.readAll()); //内容转为Utf8编码传入output
qDebug() << output; //"Your Result is:30\r\n"
QRegularExpression re(".*:+(\\d+)"); //匹配数字30
QRegularExpressionMatch match = re.match(output);
if (match.hasMatch()) {
QString result = match.captured(1);
qDebug() << result.toInt(); //30
}
qDebug() << "Done" << endl;

QCryptographicHash哈希加密

QCryptographicHash采用哈希映射特定文本加密到散列码,散列码字符来自类似base64的字符集(A-Z, a-z, 0-9, +, /),具有以下特性:

  • 不可逆:不可能从散列码恢复数据;

  • 长度固定

  • 不唯一性:不同的输入可能导致相同的散列码输出,但是这个哈希碰撞的概率极小。

常用的两种哈希映射方法是sha1md5,可用作文件校验,QCryptographicHash提供了静态方法和成员函数方法实现散列加密:

1
2
3
4
5
6
7
8
9
10
11
12
//法一:静态函数,QCryptographicHash::hash
QByteArray byteArray;
byteArray.append("Hello Eden");
QByteArray hash1 = QCryptographicHash::hash(byteArray, QCryptographicHash::Md5);
QString output1 = hash1.toHex();
qDebug() << output1; //"83e83ec8d3cdffc27620c9ff98335c36"

//法二:addData+result
QCryptographicHash hash2(QCryptographicHash::Md5);
hash2.addData(byteArray);
QString output2 = hash2.result().toHex();
qDebug() << output2; //"83e83ec8d3cdffc27620c9ff98335c36"

md5运算速度更快,而sha1安全略高于md5,但目前md5和sha1均不是绝对安全的,可经过计算机计算破解,所谓破解并不是破获原来的文本,而是找到另一组输入产生相同的散列码输出,即哈希碰撞;可通过多次加密减少哈希碰撞的概率,或使用sha2等更安全的哈希算法。