Qt输入输出类简介
![图片[1] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/96f7b741f217455cb898251b746a5222.png)
QTextStream 类(文本流)和 QDataStream 类(数据流)Qt 输入输出的两个核心类,其作用分别如下:
QTextStream 类:用于对数据进行文本格式的读/写操作,可在 QString、QIODevice或 QByteArray 上运行,比如把数据输出到 QString、QIODevice 或 QByteArray 对象上,或进行相反的操作。
QDataStream 类:用于对数据进行二进制格式的读/写操作,QDataStream 只可在QIODevice 或 QByteArray 上运行,因为 QString 只存放字符数据。
QIODevice 类是 Qt 中所有 I/O 设备的基础接口类(这是一个抽象类),也就是说 QIODevice及其子类描述的是 I/O 设备,该类为支持读/写数据块的设备提供了通用实现和抽象接口,比如 QFile、QBuffer、QTcpSocket 等。
QIODevice 把设备分为两类:随机存储设备和顺序存储设备
随机存储设备:可定位到任意位置(使用 seek()函数),随机存储设备有 QFile,QTemporaryFile,QBuffer;
顺序存储设备:不支持任意的位置存储,顺序存储设备有 QProcess、QTcpSocket、QUdpSocket 和 QSslSocket。
QTextCodec 类负责 Unicode 与各字符编码之间的转换。
QProcess 类与进程相关,QTcpSocket、QUdpSocket 等类与网络数据传输有关。
QBuffer 类为 QByteArray 提供了一个 QIODevice 接口,以允许使用 QIODevice 接口来访问 QByteArray。默认情况下,创建一个 QBuffer 时,会自动在内部创建一个 QByteArray缓冲区。
QIODevice::OpenModeFlag 枚举介绍如下:

QDataStream 类(数据流)
QDataStream 类(数据流)简介
QDataStream 类负责以二进制方式读/写程序中的对象,输入源和输出目样标可以是QIODevice、QByteArray 对象。
字节序:即多字节数据(即大于一个字节的数据)在内存中的存储顺序,有如下两种方式:
Little-Endian(LE,小端):即低位字节存储在低地址端,高位字节存储在高地址端;
Big-Endian(BE,大端):即高位字节存储在低地址端,低位字节储倣在高地址端。这是 QDataStream 的默认字节序。
比如对于整数 0x2345,若按 big-endian(大端)顺序存储,则按 0x23、0x45 的顺序存储,若按 little-endian(小端)顺序存储,则以 0x45、0x23 的顺序存储。
对象的存储和传输:若直接把一个对象保存在文件(或其他地方)上是没有意义的,因为对象中通常包含指向其他对象的指针,指针所指对象在下次运行时其内存地址很可能并不相同,因此在保存对象时,保存本次运行时指针的值就毫无意义,对此,需要采取必要的手段来解决保存对象的问题。对象的传输同样会遇到这种问题(比如在客户端和服务端传递对象时,在进程间传递对象时),解决这一问题的方法就是序列化(serializable)或称为串行化。
序列化(serializable):是把对象状态转换为可保存或可传输的形式的过程,与其对应的是反序列化,序列化和反序列化保证了数据易于存储和传输。数据通常以二进制序列的形式进行传输,因此序列化通常是把对象转换为字节序列的过程,其相反过程称为反序列化。
QDataStream 是编码信息的二进制流,它完全独立于主机的操作系统、CPU 和字节序,比如由 Windows 编写的数据流可以由运行 Solaris 的 Sun SPARC 读取。还可使用数据流来读/写原始的未编码的二进制数据。
QDataStream 实现了基本的 C++数据类型的序列化,比如 char,short,int,char *等。更复杂的数据类型的序列化是通过分解原始单元来完成的。
数据流与 QIODevice 紧密合作,QIODevice 表示一个能读/写数据的 I/O 设备,其中 QFile是常见的 I/O 设备。
写入到数据流的每一项都是以预定义的二进制格式编写的,该格式根据写入项的类型而有所不同。
QDataStream 支持的 Qt 类型有 QBrush、QColor、QDateTime、QFont、QPixmap、QString、QVariant 等类型,还包括容器类型,比如 QList、QVector、QSet、QMap 等,支持的 Qt类型的完整列表可参阅帮助文档 Serializing Qt Data Types。
对于整数,建议始终转换为 Qt 整数类型(比如 qint32 等)进入写入,并将其读入为相同的Qt整数类型,这样可以确保获取确定的大小的整数,以避免编译器和平台差异的影响(注:C++语法只规定了 int,short 等类型的最小长度,未规定最大长度)。
使用 QDataStream 读/写二进制数据的步骤如下(以读/写到 QFile 为例):
使用 QDataStream 可方便的使用>>和<<运算符对数据进行读写操作。
使用 QDataStream 读取文件步骤相对来说要多一些,需要如下步骤:
1)创建一个 QFile 对象;
2)再打开文件;
3)然后还需要创建一个 QDataStream 对象并把 QFile 对象绑定到该对象上;
4)然后才能使用>>和<<运算符进行读取操作。
QDataStream 类函数详解(目前使用频率低)
QTextStream 类(文本流)
QTextStream 类(文本流)简介
字符编码基础知识
怎样将字符转换为二进制形式进行存储,存在一个编码的问题,通常都需进行两次编码。
字符集:字符的第一次编码是将字符编码为与一个数值(如一个 10 进制整数)相对应,比如把字符 A 编码为 10 进制的 65,B 编码为 66 等。把每一个字符都编码为与一个数值对应就组成了一个字符集,比如常用的 ASCII 字符集,Unicode 字符集,GB2312 字符集等。
编码(或称为编码字符集):字符的第二次编码就是把第一次编码好的数值再编码为相应的二进制形式,这样计算机就能识别了,比如对于 Unicode 字符集有 3 种不同的二次编码方案,分别是 UTF-8(变长位),UTF-16(16 位)和 UTF-32(32 位),目前使用较多的是使用 UTF-8来存储的 Unicode 字符集。本文把第二次编码后的方案简称为编码,比如 UTF-8 编码,UTF-16 编码等。
字节顺序标记 BOM(Byte Order Mark):BOM 是出现在文本文件头部的一种用于标识文件格式的编码,UTF-16 和 UTF-32 通常使用 BOM 来表示文本的字节序,字节序对 UTF-8没有意义,因此 UTF-8 不需要使用 BOM 来表明字节序,但可使用 BOM 来表明其编码方式,通常使用 0xEF BB BF 来表明此文本是使用的 UTF-8 编码。UTF-8 不推荐使用无意义的 BOM,但很多程序在保存 UTF-8 编码的文件时仍然带有 BOM(即在文件的开头加上 0x EF BB BF 三个字节),比如 windows 的记事本等,因此在编辑 UTF-8 的文件时,需要注意该文件是否带有 BOM 的问题。
QString 和 QByteArray 简介:QString 存储一个 16 位的 QChar 字符串,其中每个 QChar 对应一个 Unicode4.0 字符(即存储的字符含有16位),对于代码值超过65536的Unicode字符使用两个连续的QChar表示。QByteArray 类用于存储原始字节和传统的 8 位以’’终止的字符串。Qt 内部大量使用了QString,因此通常应使用 QString,QByteArrayy 主要用于存储原始二进制数据。
QTextStream 基本规则
二进制文件格式更紧凑,但它是机器语言,不易于人工阅读和编辑,为此可使用文本格式来代替二进制格式。
QTextStream 类用于对数据进行文本格式的读/写操作,可在 QString、QIODevice 或QByteArray 上运行,使用 QTextStream 可方便的读/写单词、行和数字,另外 QTextStream还对字段填充、对齐和数字格式提供了格式选项的提供支持。
QTextStream 与编码和字符集:
QTextStream 在其内部使用 16 位(两字节)长的 QChar 类型存放每个字符,字符集使用Unicode,这与 C++的 iostream 不同,iostream 每个字符的类型由模板参数 charT 指定,标准库已将其特化为 char 和 wchar_t 类型,除此之外还可为 charT 指定其他类型,而QTextStream 的字符类型固定为 QChar 类型,使用此种方式简化了 Qt 流的总体结构,但也增加了字符占据的空间。
QTextStream 能在 Unicode 编码与系统的本地编码或其他任意编码间进行转换,且明确的处理了因系统的不同而导致的不同的行尾符的问题(比如,在 Windows 上行尾符是”
“,在 UNIX 或 mac OS X 上是”
“),行尾符还可在打开设备时指定QIODevice::Text 枚举来设置。
QTextStream 使用 QTextCodec 类来支持不同的字符集,默认使用QTextCodec::codecForLocale()返回的本地编码进行读/写,也可使用 QTextStream::setCodec()函数来重新设置编码。
QTextStream 支持自动 Unicode 的 BOM 检测,当启用此功能(默认)时,QTextStream将检测 UTF-16 或 UTF-32 的字节顺序标记 BOM(Byte Order Mark),并在读取时切换到适当的 UTF 编解码器。默认情况下,QTextStream 不编写 BOM,但是可以通过调用 setGenerateByteOrderMark(True)来启用 BOM。
QTextStream 有 3 种读取文本文件的方式,如下:
调用 readLine()逐行读取数据,使用 readAll()一次读取整个文件。
一个单词接一个单词的读取,单词由空格分开,且可自动跳过前导空格。通过在 QString、QByteArray 或 char*缓冲区上使用>>操作符来实现。
一个字符接一个字符的读取,通过在 QChar 或 char 类型上使用使用>>操作符来实现。可使用 skipWhiteSpace()来跳过空格。
格式控制:
QTextStream 模仿了的控制符(也称为操作器),比如可使用 dec 等流控制符以 10 进制形式显示数字,另外还可使用 setIntegerBase()、setNumberFlags()等函数来设置格式。
当从文本流中读取数字时,QTextStream 会自动检测数字的基数,比如,若数字以 0x开始,则将被假定为 16 进制形式,若以 1~9 开头,则被假定为 10 进制形式。还可使用 dec 等流控制符、setIntegerBase()函数来设置基数,从而停止自动检测。
QTextStream 还可以进行基本数字类型和字符串之间的转换。
写入文本数据比较容易,但读取就比较难了,比如:
out<<"AAA"<<"BBB" //把 AAA 和 BBB 写入流
in>>s1>>s2; //试图从流中读取 AAA 到 s1,BBB 到 s2,
若使用 QTextStream 不能获得这个结果,此时 s1=“AAABBB”,而 s2 什么也没有,若使用QDataStream 则能使 s1=“AAA”,s2=“BBB”,因为 QDataStream 在字符串数据前面保存了每个字符串的长度。
由于文本流使用缓冲区(用于存储中间数据,这减少了对设备的访问数量),所以不应该使用设备的相应函数直接读取,比如,若一个 QFile 直接使用 QFile::readLine()读取,而不是使用 QTextStream::reaLine(),那么文本流的内部位置会与文件的位置不同步。
QTextStream 类中的函数
对 QTextStream 流的操作函数
1)构造函数:
QTextStream();
QTextStream(QIODevice *device); //构造一个在设备 device 上运行的 QTextStream
QTextStream(FILE *fileHandle, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
此函数用于在控制台进行输入输出。
QTextStream(QString *string, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
构造一个在字符串 string 上运行的 QTextStream,打开模式由 openMode 指定。
QTextStream(QByteArray *array, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
构造一个在 array 上运行的 QTextStream,在内部 array 会由 QBuffer 包装。
QTextStream(const QByteArray &array, QIODevice::OpenMode openMode = QIODevice::ReadOnly);
构造一个在 array 上运行的 QTextStream,无论 openMode 的值如何,array 都以只读方式访问。
2)void flush();
刷新等待写入设备的缓冲区数据,若 QTextStream 对字符串进行操作,则此函数什么也不做。如果调用此函数,QTextStream 会将写入缓冲区中的所有数据清空到设备中,并调用设备上的 flush()。该函数的作用其实就是刷新缓冲区。
3)bool atEnd() const;
若没有更多的数据从QTextStream中读取(即到达流的末尾),则返回true,否则返回false。
4)void resetStatus(); //重置 QTextStream 的状态
Status status() const; //返回 QTextStream 的状态
void setStatus(Status status);
设置 QTextStream 的状态。直到调用 resetStatus()之前将忽略对 setStatus()的后续调用。Status 枚举见下表
![图片[2] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/f7f33d25bb51423caea733246a01710c.png)
5)QIODevice *device() const; //返回与 QTextStream 关联的当前设备,若未分配设备,则返回 0
void setDevice(QIODevice *device);
把当前设备设置为 device,若已分配了设备,则 QTextStream 在更换旧设备之前调用QTextStream::flush()。注意:此函数会把语言环境重置为默认语言环境,将编解码器重置为默认编解码器 QTextCodec::codecForLocale()
6)QString *string() const; //返回分配给 QTextStream 的 string,若未分配,则返回 0
void setString(QString *string, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
使用打开模式 openMode 重新设置 QTextStream 的设备为 string,若设备已分配,则QTextStream 在更换旧设备之前调用 QTextStream::flush()
读取流中的数据及位置函数
1)QString read(qint64 maxlen); //从流中读取 maxlen 个字符,并将其作为 QString 返回。
2)QString readAll();
从流中读取全部内容,并将其作为 QString 返回,处理大型文件时应避免使用此函数,因为会消耗大量内存。
3)QString readLine(qint64 maxlen = 0);
从流中读取一行文本,并将其作为 QString 返回,允许的最大行长度为 maxlen,若流的长度超过 maxlen,则行将在 maxlen 之后被拆分,并以部分的形式返回。若 maxlen为 0,则行可以是任意长度。返回的行没有行尾字符(“
“或”
“),若流已到达文件末尾,则返回空的 QString。
4)bool readLineInto(QString *line, qint64 maxlen = 0); //qt5.5
从流中读取一行文本到 line,若 line 为 0,则不存储读取的行。允许的最大行长度为maxlen,若流的长度超过 maxlen,则行将在 maxlen 之后被拆分,并以部分的形式返回。若 maxlen 为 0,则行可以是任意长度。返回的行没有行尾字符(“
“或”
“),若流已到达文件末尾,则返回空的 QString。若流已读取到文件末尾或发生错误,则返回false,否则返回 true。
5)bool seek(qint64 pos);
查找设备中的位置 pos,若找到,则返回 true,否则返回 false
6)qint64 pos() const;
返回与流当前位置对应的设备位置,或当发生错误时返回−1(比如没有设备),此函数可能很昂贵。
7)void skipWhiteSpace();
从流中读取并丢弃空白字符,直到检测到非空白字符,或直到 atEnd()返回 true。此处的空白字符是指 QChar::isSpace()函数返回 true 的字符。
示例:使用 QTextStream 流读取文件的内容
#include<QtWidgets>
int main(int argc, char *argv[])
{
//QApplication aa(argc,argv);
QFile f("F:/1.txt");
f.open(QIODevice::ReadOnly);
QTextStream in(&f); in.setCodec("GB18030");
QChar c;
//1、逐字符读取的方法
in>>c; //从 1.txt 读取第一个字符
qDebug()<<c; //输出u4e2d(这是“中”字的 Unicode 编码)
in>>c; //继续读取第 2 个字符
qDebug()<<c; //输出u6587(这是“文”字的 Unicode 编码)
//2、一个单词接一个单词的读取
in.seek(0); //把位置设置为 0,以便从头开始读取
QString s;
in>>s; //读取一个单词到 s 中(单词由空格分开),
qDebug()<<s; //输出“中文示例 0”。
in>>s; //继续读取下一个单词到 s 中,
qDebug()<<s; /*输出“aaa1”。>>运算符会自动跳过前导空格,所以读取到的单词前面
没有空白符*/
//3、读取指定个数的字符
in.skipWhiteSpace(); //跳过空白。
s=in.read(10); //继续读取 10 个字符,并把读取到的字符保存到 s 中
qDebug()<<s; //输出“aaa2 中文示例 1”
//4、逐行读取
s=in.readLine(); //继续读取余下的整行文本,并把结果保存到 s 中
qDebug()<<s; /*输出“ aaaa3 aaaa4 中文示例 2 12389 83”,注意:因为为跳过空
白,所以最前面有一个空白字符*/
in.seek(0); //重置位置
s=in.readLine(30); /*读取30个字符或整行(本行大于30个字符,因此只读取30个字符),
并把结果保存到 s 中*/
qDebug()<<s; //输出"中文示例 0 aaa1 aaa2 中文示例 1 aaaa3 aa"
//5、读取整个文本
in.seek(0);
s=in.readAll();
qDebug()<<s; /*输出"中文示例 0 aaa1 aaa2 中文示例 1 aaaa3 aaaa4 中文示例 2 12389
83
bbb1 bbb2 中文示例 3 bbbb3 bbbb4 中文示例 4 12389 83
ccc1
ccc2 中文示例 5 cccc3 cccc4 中文示例 6 12389 83
",由输出可见,
readAll()函数包含了行尾符"
"*/
//6、使用循环逐行读取整个文件。
while(!in.atEnd()) s+=in.readLine();
qDebug()<<s;}

编码相关函数
1)QTextCodec *codec() const; //返回当前流的编解码器
void setCodec(QTextCodec *codec);
void setCodec(const char *codecName);
设置流的编解码器,其中 codecName 是以字符串的形式指定编解码器,若无法识别该字符串,则不会发生任何事情,codecName 的值有:“ISO 8859-1”, “UTF-8”、“UTF-16”、“GB 18030”、”Big5″等,详细的取值详见 QTextCodec 类。
2)QLocale locale() const; //返回区域,默认语言环境是 C
void setLocale(const QLocale &locale); //设置流的区域为 locale
3)bool autoDetectUnicode() const; //是否启用自动 Unicode 检测,默认为 true(即,启用)
void setAutoDetectUnicode(bool enabled);
若 enabled 为 true,则 QTextStream 会尝试查看流数据来检测 Unicode 的字节顺序标记BOM,若找到此标记,则 QTextStream 将使用 UTF 编解码器替换当前编解码器。
4)bool generateByteOrderMark() const;
若 UTF 编解码器产生 BOM,则返回 true,否则返回 false。默认为 false
void setGenerateByteOrderMark(bool generate);
若 generate 为 true 且使用了 UTF 编解码器,则 QTextStream 将在把数据写入设备之前插入 BOM,若 generate 为 false,则不会插入 BOM。该函数需在写入数据之前调用。
格式控制函数
1)void reset(); //重置 QTextStream 的格式选项,使其恢复到原始构造状态。
2)int fieldWidth() const; //返回当前字段的宽度
void setFieldWidth(int width);
设置当前字段的宽度,若 width 为 0(默认值),则字段宽度等于生成的文本的长度。字段宽度适用于调用此函数后添加到此流的每个元素。
3)QChar padChar() const; //返回当前的填充字符
void setPadChar(QChar ch);
设置填充字符为 ch,默认为 ASCII 空格字符,或 QChar 的 0x20,生成文本时,字符ch 用于填充字段中的空格
4)FieldAlignment fieldAlignment() const; //返回当前字段的对齐方式,FieldAlignment 枚举见下表
void setFieldAlignment(FieldAlignment mode); //设置字段的对齐方式,与 setFieldWidth()一起使用。
![图片[3] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/8a8dbbfd9f274eccae4bdccc88eba4e0.png)
5)int integerBase() const; //返回整数的基数
void setIntegerBase(int base);
设置整数的基数,base 可取值为 2、8、10、16(分别表示二进制、8 进制等),若 base为 0,则 QTextStream 将通过检查流上的数据来检测其基数。生成数字时,QTextStream假设 base 为 10,除非明确设置 base
6)NumberFlags numberFlags() const; //返回当前的数字标志,枚举 NumberFlag 见下表
void setNumberFlags(NumberFlags flags); //设置数字标志
![图片[4] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/a4bb5c5e80814e6ba15153aade1e68cf.png)
7)RealNumberNotation realNumberNotation() const; //返回当前的实数表示法,枚举见下表
void setRealNumberNotation(RealNumberNotation notation); //设置实数表示法
![图片[5] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/ad11686881784d7eae628f5ba37b7fd3.png)
8)int realNumberPrecision() const; //返回当前实数的精度
void setRealNumberPrecision(int precision); //设置实数的精度。精度不能为负值,默认为 6。
9)QTextStream 类还包含如下形式的一系列的重载<<和>>运算符函数,他们的形式都是一样
的,只是形参的类型不相同,其余的函数从略。
QTextStream &operator<<(QChar c); QTextStream &operator<<(char c);
QTextStream &operator<<(signed short i); QTextStream &operator<<(unsigned short i);
QTextStream &operator<<(signed int i); QTextStream &operator<<(unsigned int i);
示例:QTextStream 的格式控制
#include<QtWidgets>
int main(int argc, char *argv[]){
QFile f("F:/1.txt"); f.open(QIODevice::WriteOnly);
QTextStream out(&f);
/*未设置格式前输入 1.txt 的内容,QTextStream 能自动实别数字,0xB 会被保存为 10 进制的 11。
注意:123 是字符串,不是数字。*/
out<<"123
"<<456<<"
"<<0xB<<"
";
out.setFieldWidth(10); //设置字段宽度为 10
out.setPadChar('*'); //设置填充字符为*
out.setFieldAlignment(QTextStream::AlignRight); //设置文本在字段间的对齐方式
out.setIntegerBase(16); //数字以 16 进制保存
//显示数字基数并以大写字母形式显示基数前缀
out.setNumberFlags(QTextStream::ShowBase|QTextStream::UppercaseBase);
out<<"123
" /*输入第 1 个字段到 1.txt,在 123 之前填充 5 个*,注意"
"会
占两个字符宽度*/
<<"aaa" //输入第 2 个字段,在 aaa 之前填充 7 个*
<<"bbb"<<"
" /*输入第 3 和第 4 个字段,注意:这里是两个字段而不是一个,因
此会在 bbb 之前填充 7 个*,在"
"之前填充 8 个*。*/
<<456<<"
"; } /*输入第 5 和第 6 个字段。填充字符原理同上。数字 456 被以 16 进
制的形式输入到 1.txt 中*/

QFile类(文件)
QFile 类简介
QFile 基础
QFile 类继承自 QFileDevice 类,QFileDevice 又继承自 QIODevice 类。
QFile 类提供了一个用于读取/写入文件的接口,是一种读写二进制文件、文本、资源的 I/O 设备。
默认情况下 QFile 假定为二进制,即不对存储在文件中的字节执行任何转换。
与其他 QIODevice 不同,QFile 不会发送 QIODevice::aboutToClose(),QIODevice::btyesWritten()、QIODevice::readyRead()信号,这意味着 QFile 不适合读取/写入某些类型的文件(比如 Unix 上的 device 文件)。
读写文件内容的方法
QFile 可通过自身直接对文件进行读写,比如,使用从 QIODevice 类继承来的 read()、readAll()、readLine()等函数进行读写,这些函数的原型详见后文;还可使用QTextStream 或 QDataStream 进行读写(这两种方法在前文已讲解过)。
在 Unix 上,不能使用 QFileDevice::atEnd()来判断文件是否还有更多的数据,因为在Unix 上有一些特殊的系统文件(比如,在/proc 中),它的 QFile::size()总是返回 0,但仍可从这样的文件中读取数据,而 QFileDevice::atEnd()函数对于大小为 0 的文件将返回true,因此不能使用atEnd()来判断文件是否还有数据。此时应反复的调用readAll()、read()或 readLine()来读取数据,直到无数据读取为止。下面为其示例代码:
QTextStream in(&f); QString s;
QString s1=in.readLine(); //读取文件内容并保存到 s1 中
while(!s1.isNull()) //判断 s1 是否为空,以此来判断是否无数据可读取
{
s += s1; //把文件的所有内容保存到 s 中
……} //其他代码
文件名及目录分隔符
目录分隔符:QFile 使用的目录分隔符为”/“,不支持其他分隔符(比如” “)。
文件名:当使用 QFile、QFileInfo 和 QDir 访问 Qt 文件系统时,可以使用 Unicode 文件名。在 Unix 上,文件名被转换为 8 位编码。可以使用 QFile::encodeName()和QFile::decdeName()函数在 Unicode 文件名和 8 位文件名之间进行转换。
文件权限处理
在 Unix-like(类 Unix)和 Windows 上,文件权限的处理方式不同,在 Unix-like 上的不可写目录中,无法创建文件,但在 Windows 上却并非总是如此。
Qt 对文件权限的理解是有限的,这对 QFile::setPermissions()函数影响较大,在 Windows上,Qt 将仅设置传统的 read-only(只读)标志,且只在没有任何的 Write*标志未设置时才设置。Qt 不处理访问控制列表(ACL,access control lists),这使得此函数对 NTFS 卷几乎无用,但仍可用于使用 VFAT 文件系统的 USB 存储。
下表是一些常用函数及其功能:

QFile 类中的函数
文件操作函数
1)构造函数
QFile();
QFile(const QString &name);
QFile(QObject *parent);
QFile(const QString &name, QObject *parent);
2)virtual bool open(OpenMode mode);
QIODevice::open()的重新实现,使用模式 mode 打开文件,若成功,则返回 true,否则返回 false。在 WriteOnly 或 ReadWrite 模式下,若文件不存在,则此函数在打开之前会尝试创建新文件。
3)bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle);
bool open(int fd, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle);
在模式 mode 下打开已存在的文件句柄 fh 或文件描述符 fd,若成功,则返回 true,否则返回 false。
参数 handleFlags 用于指定其他选项,其枚举见下表。
![图片[6] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/d7b01d3ec8484c929289192ed1cff9aa.png)
使用此函数打开 QFile 时,close()的行为由 QFileDevice::AutoCloseHandle 标志控制。如果指定了 QFileDevice::AutoCloseHandle,并且此函数成功,则调用 close()将关闭所采用的句柄。否则,close()实际上不会关闭文件,而是只刷新它。
注意:若 fh 不是常规文件,例如,它是 stdin、stdout 或 stderr,那么可能无法使用 seek()。在这些情况下,size()返回 0。
由于此函数在未指定文件名的情况下打开文件,因此不能将此 QFile 与 QFileInfo一起使用。
4)virtual void QFileDevice::close(); //虚拟的
QIODevice::close()的重新实现。调用 QFileDevice::flush()并关闭文件。
5)bool remove();
static bool remove(const QString &fileName); //静态的
删除文件 fileNmae 或由 fileName()指定的文件,若成功,则返回 true,否则返回 false
6)bool copy(const QString &newName);
static bool copy(const QString &fileName, const QString &newName); //静态的
把文件 fileName 或由 fileName()当前指定的文件复制到名为 newName 的文件中,若成功,则返回 true,否则返回 false。
注意:若 newName 已存在,则该函数会返回 false,也就是说,该函数不会覆盖newName。
在复制之前,非静态函数会关闭源文件。静态函数不会关闭源文件,其实调用静态函数复制文件,根本就不需要创建与源文件关联的 QFile 对象,所以不存在关闭源文件的问题。
7)virtual bool resize(qint64 sz); //QFileDevice::resize()的重新实现
static bool resize(const QString &fileName, qint64 sz);//静态的
把文件 fileName 的大小设置为 sz,若设置成功,则返回 true,否则返回 false。
若 sz 大于 fileName 的大小,则新字节被设置为 0,若 sz 较小,则将文件截断。
注意:若文件不存在,此函数可能会失败。
8)virtual qint64 size() const; //QIODevice::size()的重新实现。获取文件的大小
9)bool exists() const;
static bool exists(const QString &fileName);//静态的
若文件 fileName 或由 fileName()指定的文件存在,则返回 true,否则返回 false
文件的复制(其原理及说明见示例后的图示) :
#include<QtWidgets>
int main(int argc, char *argv[]){
QFile f("F:/1.txt"); f.open(QIODevice::ReadWrite);
int i=QFile::copy("F:/1.txt","F:/3.txt"); //复制失败(因为 3.txt 已存在),i=0;
i=f.copy("F:/3.txt"); //复制失败,i1=0;原因同上。
i=f.copy("F:/4.txt"); //复制成功,i=1,同时关闭源文件 f。
QTextStream out(&f); out<<444; //写入失败,文件 f 已关闭。
//使用静态函数复制文件
QFile f1("F:/2.txt"); f1.open(QIODevice::ReadWrite);
i=QFile::copy("F:/2.txt","F:/5.txt"); //复制成功,i=1;但不会关闭文件 f1,
QTextStream out1(&f1); out1<<5555; //写入成功。
i=QFile::copy("F:/3.txt","F:/6.txt"); } /*复制成功,i=1;静态函数可直接复制文件,不需要
创建与源文件关联的 QFile 对象。*/

文件的读写函数
(以下函数均继承自父类,其使用方法与 QTextStream 中的相应函数类似)
1)qint64 QIODevice::read(char *data, qint64 maxSize);
从设备读取 maxSize 个字节的数据到 data,并返回读取的字节数,若产生错误,返回−1,若没有更多数据可读取时,返回 0。注意:在流的末尾读取也被认为是错误,此时也会返回−1。
2)QByteArray QIODevice::read(qint64 maxSize);
从设备中读取 maxSize 字节的数据,并以 QByteArray 的形式返回,此函数无法报告错误
3)qint64 QIODevice::readLine(char *data, qint64 maxSize);
从设备读取一行 ASCII 字符,最大字节数为 maxSize−1,并把字符存储在 data中,并返回读取的字节数。
若不能读取行,但未发生错误,则返回 0,若发生错误,则此函数返回可读取的长度,若未读取任何内容,则返回−1。
终止符’’总是附加到数据中,因此 maxSize 必须大于 1。
读取数据直到产生以下条件之一:
1.读取到一个’
’字符,在 windows 上,换行符被替换为’
’
2.读取了 maxSize−1 个字节
3.检测到设备数据结束
4)QByteArray QIODevice::readLine(qint64 maxSize = 0);
从设备中读取一行数据,但不超过 maxSize,并以 QByteArray 的形式返回,此函数无法报告错误
5)QByteArray QIODevice::readAll();
从设备读取所有剩余数据,并以 QByteArray 的形式返回,此函数无法报告错误
6)qint64 QIODevice::write(const char *data, qint64 maxSize);
把最多 maxSize 个字节的数据 data 写入设备,并返回实际写入的字节数,若发生错误,则返回−1。
7)qint64 QIODevice::write(const char *data);
把以 0 结尾的 8 位字符串数据 data 写入设备,并返回实际写入的字节数,若发生错误,则返回−1。
8)qint64 QIODevice::write(const QByteArray &byteArray);
把内容 byteArray 写入设备,并返回实际写入的字节数,若发生错误,则返回−1。
9)bool QIODevice::getChar(char *c);
从设备读取一个字符,并将其保存在 c 中,若 c 为 0,则丢弃该字符,若读取成功,则返回 true,否则返回 false。
10)bool QIODevice::putChar(char c);
把字符 c 写入设备,若成功,则返回 true,否则返回 false。
11)void QIODevice::ungetChar(char c);
把字符 c 放回设备,除非位置为 0,否则递减当前位置,该函数通常被称为 getChar()的撤销操作,若字符 c 未从设备读取,则行为是未定义的。注意:当事务正在进行时,此函数不可用。
文件名相关函数
1)virtual QString fileName() const; //虚拟的
QFileDevice::fileName()的重新实现,返回由 setFileName()或 QFile 构造函数设置的文件名称
2)void setFileName(const QString &name);
设置文件的名称为 name,名称可以没有路径、相对路径或绝对路径。若文件已打开,请不要调用此函数。若 name 不含路径,则使用的路径是调用 open()时应用程序的当前目录路径。
3)bool rename(const QString &newName);
static bool rename(const QString &oldName, const QString &newName);//静态的
把文件 oldName 或由 fileName()指定的文件重命名为 newName,若成功,则返回true,否则返回 false,
注意:若 newName 已存在,则该函数会返回 false。
在复制之前,非静态函数会关闭源文件。静态函数不需要创建与源文件关联的QFile 对象,所以不存在关闭文件的问题。
4)static QString decodeName(const QByteArray &localFileName); //静态的
static QString decodeName(const char *localFileName); //静态的
返回 localFileName 的 Unicode 版本,即把 localFileName 转换为 Unicode 版本的文件名。
5)static QByteArray encodeName(const QString &fileName);//静态的
把 fileName 转换为由用户区域设置确定的本地 8 位编码。硬编码到应用程序中的文件名应仅使用 7 位 ASCII 文件名字符。
文件链接相关
1)bool link(const QString &linkName);
static bool link(const QString &fileName, const QString &linkName); //静态的
创建一个名为 linkName()的链接(类似于 Windows 下的快捷方式),该链接指向文件fileName 或当前由fileName()指定的文件,若成功,则返回true,否则返回false。
注意:在 Windows 上创建链接,linkName 必须具有.lnk 后缀(即文件扩展名为.lnk)
2)QString symLinkTarget() const;
static QString symLinkTarget(const QString &fileName);//静态的
返回符号链接(或快捷方式)所引用的文件或目录的绝对路径,若调用该函数的 QFile对象不是符号链接或 fileName 不是符号链接,则返回空字符串。若符号链接指向一个现有文件,则 QFile::exists()返回 true。
文件权限相关
1)virtual Permissions permissions() const; //QIODevice::Permissions()的重新实现
static Permissions permissions(const QString &fileName); //静态的
返回文件 fileName 的 QFile::Permission 标志的完整的按位或组合。枚举见下表
2)virtual bool setPermissions(Permissions permissions);
static bool setPermissions(const QString &fileName, Permissions permissions);//静态的
QFileDevice::setPermissions 的重新实现。将文件的权限设置为 permissions,若成功,则返回 true,若无法修改权限,则返回 false。此函数不会处理 ACL,这可能会限制其有效性。

QDir类(目录)
QDir类简介
QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统
Qt 使用“/”作为通用目录分隔符,与“/”在 URL 中用作路径分隔符的方式相同。如果您总是使用“/”作为目录分隔符,Qt 将转换您的路径以符合底层操作系统。
QDir 可以使用相对路径或绝对路径指向文件。绝对路径以目录分隔符开头(在 Windows 下,可以选择以驱动器规格开头)。相对文件名以目录名或文件名开头,并指定相对于当前目录的路径。
QDir类常用函数
1)QDir(const QString &path = QString())
构造函数
2)bool exists() const;
判断路径是否存在
3)bool isFile() const;
判断是否是文件
4)bool isDir() const;
判断是否是文件夹
5)QString absolutePath() const;
获取当前路径
6)QString fileName() const;
获取文件名
7)QString dirName() const;
获取文件目录
8)qint64 size() const;
获取文件大小
9)QDateTime created() const;
获取文件的创建时间
10)QDateTime lastModified() const;
获取文件的最后修改时间
11)bool QDir::mkdir(const QString &dirName) const;
用于在文件系统中创建一个新的目录,但要创建多级目录的话,还是要调用mkpath函数
12)bool QDir::mkpath(const QString &dirPath) const;
用于在文件系统中创建一个目录,包括其所有的父目录。如果目录成功创建或已经存在,则返回true;否则返回false。如果路径中的某个目录不存在,函数会递归地创建缺失的目录层级。
13)void QDir::setNameFilters(const QStringList &nameFilters);
用于设置目录对象的名称过滤器来限制列出或搜索的文件或目录的类型。
14)QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, QDir::Filters filters = NoFilter, QDir::SortFlags sort = NoSort) const;
用于搜索名称过滤器的文件列表,并将其返回。
QDir::Filters 是 QDir 类的一个枚举类型,用于指定在查询目录内容时要应用的过滤器。以下是 QDir::Filters 的一些常见值:
QDir::NoFilter: 不应用任何过滤器,返回所有的文件和目录。
QDir::Dirs: 只返回目录,不包括子目录。
QDir::Files: 只返回文件。
QDir::Drives: 只返回驱动器(仅适用于 Windows 操作系统)。
QDir::AllDirs: 返回所有的目录,包括子目录。
QDir::AllEntries: 返回所有文件和目录。
QDir::Readable: 返回可读取的文件。
QDir::Writable: 返回可写入的文件。
QDir::Executable: 返回可执行的文件。
QDir::Modified: 返回被修改过的文件。
QDir::Hidden: 返回隐藏的文件和目录。
QDir::System: 返回系统文件和目录。
QDir::NoSymLinks: 不返回符号链接。
QDir::NoDotAndDotDot: 不返回 “.” 和 “…” 目录。
QDir::SortFlag 是一个枚举类型,用于指定 QDir 类中的排序选项。它定义了以下常用的参数:
QDir::Name:按文件名排序。
QDir::Time:按文件的最后修改时间排序。默认情况下,最新修改的文件(最近的时间戳)会出现在列表的顶部。
QDir::Size:按文件大小排序。
QDir::Type:按文件类型排序。
QDir::NoSort:不对文件进行排序,保持原始顺序。
QDir::DirsFirst:首先显示文件夹(目录),然后是文件。
QDir::DirsLast:首先显示文件,然后是文件夹(目录)。
QDir::Reversed:反转排序顺序。
该函数应用示例如下:
QString dir_str = "image/" + QDate::currentDate().toString("yyyy-mm-dd");
QDir dir(dir_str );
if(!dir.exists())
{
dir.mkpath(dir_str );
}
QStringList filter;
filter << "*.bmp";
dir.setNameFilters(filter);
QFileInfoList fileInfoList = dir.entryInfoList(filter,QDir::NoFilter,QDir::Time | QDir::Reversed);
if(fileInfoList.cout() > 100)
{
//移除一个文件(bmp图像)
QFile::remove(fileInfoList.at(0).absoluteFilePath());//移除排序后的第一个bmp图像文件
}
else
{
//保存一个文件(bmp图像)
}
15)QStringList QDir::entryList(const QStringList &nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const;//滤波器nameFilters是手动设置
QStringList QDir::entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const;//滤波器filter是枚类型
获取指定目录下的文件和目录列表,这个一般用的不多,一般用上面的那个多
Qt 资源文件简介
资源系统是一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件(前面所讨论的数据都存储在外部设备中)。若应用程序始终需要一组特定的文件(比如图标),则非常有用。
资源系统基于 qmake,rcc(Qt 的资源编译器,用于把资源转换为 C++代码)和 QFile。
在可执行文件中嵌入数据有利于创建独立的可执行文件,但由于必须容纳被嵌入的数据,因此,可执行文件本身会变得比较大。
资源收集文件(.qrc):用于指定与程序关联的资源,该文件是一种基于 XML 的文件格式,该文件大致内容如下:
<RCC>
<qresource prefix="/">
<file>1i.png</file>
<file>aaa/1hs.png</file>
<file>aaa/1m.png</file>
</qresource>
</RCC>
其中 1i.png、aaa/1hs.png、1m.png 就是.qrc 文件列出的资源,下面示例为使用资源设置按钮图标的示例代码
QPushButton *pb=new QPushButton("AAA");
pb->setIcon(QIcon(":/aaa/1m.png")); //其中":/" 是访问资源的前缀
资源基本规则:
列出的资源文件必须与.qrc 文件或其子目录位于同一目录中。
可以使用“ 😕 ”前缀访问资源。比如”:/aaa/1m.png”
需要把 qrc 文件添加到 pro 文件中,比如RESOURCES += gg.qrc //其中 gg.qrc 为需要添加的 qrc 文件
默认情况下,资源会被压缩,可以关闭压缩(需使用命令行参数来关闭,本文从略)
资源收集文件基本语法
资源前缀:使用 qresource 标记的 prefix 属性添加资源前缀,资源前缀主要用于对添加的资源的一些说明(可以为空),比如
<qresource prefix="/image">
<file>1i.png</file>
</qresource>
此时访问资源方法为”:/image/1i.png”
资源别名:使用 file 标记的 alias 属性更改,比如
<qresource prefix="/image">
<file alias = "xxx.png">aaa/1hs.png</file>
</qresource>
此时应这样访问资源”:/xxx.png”
qrc 文件可在记事本中进行编辑,编辑好之后只需把记事本的后缀修改为 qrc 即可,此时
需要在 pro 文件中手动添加 qrc 文件。
在 Qt Creator 中编辑资源的方法
创建 qrc 文件:在 Qt Creator 中创建 qrc 文件,此种方法 Qt 会自动向 pro 文件中添加创建的 qrc 文件,其步骤为:在项目名上右击(如下图左侧),然后选择“添加新文件…”,弹出对话框,在对话框左侧选择“Qt”,然后在右侧选择“Qt Resource File”,然后点击“Choose…”按钮,接下来输入 qrc 文件的文件名,其余选项保持默认即可。添加qrc 文件后的项目如下图右侧所示
![图片[7] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/0a62a6d0f83b4a06821bf6a975a9ff6e.png)
编辑qrc文件:在创建的qrc文件上右击(见以下第1幅图),然后把光标移至“Open With”,若选择“资源编辑器”,则可使用 Qt 资源编辑器编辑 qrc 文件(见以下第 2 幅图),若选择“普通文本编辑器”,则 qrc 文件会以文本的形式打开,此时可看到 qrc 文件的内容,并可以文本的形式进行编辑。
![图片[8] - Qt文本读写之一:输入输出类和文件操作 - 宋马](https://pic.songma.com/blogimg/20250505/2c6d0fc61d2e4bb896a36dce5fdb40f3.png)




















暂无评论内容