下图展示 QT 中流的框架,含两个核心类 QTextStream 以及 QDataStream
QTextStream
对数据进行文本格式的输入/输出
QDataStream
对数据进行二进制格式的输入/输出
QFile
,负责文件的处理。
QTemporaryFile
创建并访问临时文件。
QBuffer
负责以 QIODevice 的接口访问一个 QByteArray 对象。
QProcess
负责以进程的形式启动一个外部程序,并和该进程进行通信。
QTcpSocket
与 QUdpSocket 负责使用 TCP、UDP 协议进行网络数据的发送和接收。
QTextCodec
负责 Unicode 与各种字符编码方式之间的转换。
QLocale
负责实现各种区域文化。
UNIX 系统中路径分割符为“/”,而 Windows 系统的为“\”
Qt 使用类 QFileInfo 表示一个目录项的属性,类名中的“File”并不仅仅表示文件,而是泛指所有类型的目录项。
类 QDir 刻画一个目录的详细信息。
成员函数 entryInfoList(),返回该目录下子目录、文件以及链接的信息。
无论对于什么操作系统,子目录之间的分隔符都应该为“/”
//包含Qt框架中的QFile和QDebug库
#include
#include
int main()
{
//定义一个QFile对象f,并指定要打开的文件路径
QFile f("data/test.txt");
//以只读文本模式打开文件,如果打开失败,则返回-1,表示程序发生错误
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
return -1;
//将文件中的所有内容读取到一个QByteArray对象中
QByteArray data = f.readAll();
//输出QByteArray对象data的内容到控制台
qDebug() << data;
return 0;
}
QTextStream
在其内部使用两个字节长的 QChar 类型存放每个字符,使用 Unicode 编码方式
使用 QTextCodec
进行编码转换
#include //包含Qt框架中的QFile库
#include //包含Qt框架中的QTextStream库
int main(int argc, char *argv[])
{
//定义一个QFile对象src_f,并指定要打开的文件路径
QFile src_f("data/latin1.txt");
//以只读模式打开文件,如果打开失败,则返回-1,表示程序发生错误
if (!src_f.open(QIODevice::ReadOnly))
return -1;
//创建一个QTextStream对象in,并将其与QFile对象src_f关联
QTextStream in(&src_f);
//设置QTextStream对象in的编码格式为Latin1
in.setCodec("latin1");
//将文件中的所有内容读取到一个QString对象data中
QString data = in.readAll();
//定义一个QFile对象dest_f,并指定要打开的文件路径
QFile dest_f("data/unicode.txt");
//以只写模式打开文件,如果打开失败,则返回-1,表示程序发生错误
if (!dest_f.open(QIODevice::WriteOnly))
return -1;
//创建一个QTextStream对象out,并将其与QFile对象dest_f关联
QTextStream out(&dest_f);
//设置QTextStream对象out的编码格式为UTF-16
out.setCodec("UTF-16");
//将QString对象data中的内容写入到文件中
out << data;
return 0;
}
QDataStream 可以处理自定义类型
用户 struct 定义新的结构体,并通过运算符重载的方式,搭配友元实现
struct ColorText{
QString text;
QColor color;
};
QDataStream& operator << (QDataStream & stream, const ColorText & data)
{
stream << data.text << data.color;①
return stream;
}
QDataStream& operator >> (QDataStream & stream, ColorText & data)
{
stream >> data.text >> data.color;②
return stream;
}
int main()
{
ColorText data;
data.text = "Red"; data.color = Qt::red;
QFile file( "test.dat" );
if( !file.open( QIODevice::ReadWrite) ) return -1;
QDataStream stream( &file );
stream << data;
file.seek(0); stream >> data;
file.close();
qDebug() << data.text << " " << data.color;
}
QLocale
为每种区域文化定义了统一的名字,这个名字不会随着操作系统、编译器平台的变化而变化
QLocale
的静态成员函数 system()返回这个区域文化。
Qt 应用程序本身会有一个默认的区域文化,构造函数 QLocale()返回的就是后者。起初,程序默认的区域文化被设
QTextStream out( stdout, QIODevice::WriteOnly);
int main( )
{
double x = 123.456;
out.setLocale( QLocale(QLocale::German) ); ①
out << fixed << x << endl;
}
隐式共享定义:一个类的多个对象所占用的内存是相互独立的。如果其中某些对象数据成员的取值完全相同,我们可以令它们共享一块内存以节省空间。只有当程序需要修改其中某个对象的数据成员时,我们再为该对象分配新的内存。
d-pointer:把与主类密切相关的数据成员抽离作为一个私类,主类中再定义一个指针指向该私类
QString 中的成员函数 toCaseFolded()
就用到了隐式共享技术
它使用引用计数的方式判断字符串是否相同,如果相同,则共享一块内存地址
Qt 常在主类的名字后面加上后缀“Private”或者“Data”形成从类的名字
为了能够共享数据,我们必须将类中的数据分离出来,定义在一个单独的类中,再定义一个指针指向这个新类。
这个指针就被称为 d-pointer,这个模式就被称为 d-pointer 模式。
包含有 d-pointer 的那个类被称为主类,d-pointer 所指的那个类被称为从类。
采用动态链接方式时,客户只需要更新 Qt 的动态链接库,不需要重新编译、部署 Qt 应用程序。
如果在这种情形下这些 Qt 应用程序仍然能够正常工作,我们称这个 动态链接库是二进制兼容的
程序员不可以添加、删除非静态数据成员,不可以更改非静态数据成员的定义顺序、类型
二进制兼容性通常包括以下三个方面
D-pointer
模式用于实现类的私有数据封装和二进制接口兼容性
实现 d-pointer 模式的主要步骤:
为便于跨平台,QT 研发出了 QTL(类似于 Cpp 的 STL),但是其运行速度较慢
几种必备容器(单类型容器)
QVector
将其所有元素存放在一块连续的内存中。随机访问的速度很快,但是插入/删除操作很慢。QStack
是QVector
的子类,实现栈的功能QList
在内部使用一个指针数组指向容器元素。能够快速随机访问每个元素。在容器首、尾添加元素的速度也较快。QStringList
是 QList
的子类,能高效地处理字符串列表。QQueue
是 QList
的子类,实现了队列的功能。QLinkedList
能够在很短而且固定的时间内完成元素的插入/删除操作,但是排序、查找操作却较慢。键值对类型容器
QMultiMap
QHash
QSet
QCache
foreach 遍历容器的时候,接收的第一个参数表示 foreach 得到的元素,这里必须使用 typedef 预定义类型,然后直接使用
就如下方代码的 foreach( pair_type element, list)
,你不可以把 pair_type 更换为 QPair
typedef QPair<string,double> pair_type;
QList< pair_type > list;
list << pair_type("pi",3.14) << pair_type("e", 2.718);①
foreach( pair_type element, list)②
cout << element.first << " " << element.second << endl;
只要一个容器内部的迭代器支持这些基本操作,该函数模板就可以操作这个容器。这样的函数模板被称为 通用算法(algorithm)
通用算法 qSort
使用快速排序算法,将一个元素序列排成升序
对于有序容器,通用算法 qBinaryFind
使用二分搜索算法
qUpperBound
在一个元素序列中寻找最后一个大于指定值的元素,返回指向该元素的一个迭代器
无论容器是否有序,qFind
在容器中逐个搜索与某个指定值相等的元素,并返回一个指向该元素的迭代器。
qCount
计算某个值在容器中出现的次数。
qDeleteAll
调用 C++运算符 delete,析构容器中的元素。
qEqual
比较两个元素序列是否相等。
qSwap
调换两个元素的值。
QTL 提供了类似于 CPP 中的“谓词”操作
即类似于 CPP 中的 sort 函数,最后一个参数为控制排序方式的匿名回调函数
下图即使用了 QT 自己提供的成型谓词 qLess
来进行降序排列
QList<int> ql;
ql << 4 << 3 << 2 << 1 << 0;
qSort(ql.begin(), ql.end(), qLess<int>() );
一段代码,自己体会,不去解释,学学就懂
/**
* @brief 保存词典到文件中
*
* @param dict 词典对象的引用
* @param fname 要保存的文件名
* @return int 如果保存成功返回 0,否则返回 -1
*/
int save_dict_map(dict_type& dict, char* fname)
{
QFile dictf(fname); // 创建一个 QFile 对象,并指定文件名
if (!dictf.open(QIODevice::WriteOnly)) return -1; // 尝试以只写方式打开文件,如果失败则返回 -1
QDataStream ds(&dictf); // 创建一个 QDataStream 对象,并将其与 QFile 关联
ds << dict; // 将词典对象保存到 QDataStream 中
cout << fname << " saved\n"; // 输出保存成功的消息
}
/**
* @brief 从文件中加载词典
*
* @param dict 词典对象的引用
* @param fname 要加载的文件名
* @return int 如果加载成功返回 0,否则返回 -1
*/
int load_dict_map(dict_type& dict, char* fname)
{
QFile dictf(fname); // 创建一个 QFile 对象,并指定文件名
if (!dictf.open(QIODevice::ReadOnly)) return -1; // 尝试以只读方式打开文件,如果失败则返回 -1
QDataStream ds(&dictf); // 创建一个 QDataStream 对象,并将其与 QFile 关联
ds >> dict; // 从 QDataStream 中加载词典对象
cout << fname << " loaded\n"; // 输出加载成功的消息
}
容器元素的类型被表示为 QList 的模板参数 T
如果 T 占用的内存较多,QList 将每个容器元素存放在堆中,再维护一个指针数组,指向这些元素
对 QList 的插入或者删除操作会比单向链表的要稍慢,因为需要使用标准函数 memmove()
来移动数组中的指针