
前言:
- Qt是C++一个开发框架,具有跨平台特性。
- 这篇是作者大二学习的时候做的笔记,有可能有错误,请各位批评指正。
- 这篇记录Qt文件操作,当然更详细请看Qt文档或者AI
- 欢迎大家收藏 + 关注,作者将会持续更新。
文章目录
I/O
Qt中的I/O操作提供了统一接口简化了文件与外部的操作方式。I/O的本质是对连续空间的数据读写。
QIODevice为支持读写数据块(如:QFile、QBuffer和QTcpSocket)的设备提供了通用实现和接口抽象。QIODevice是抽象的,不能实例化
I/O设备类型
- 顺序存储设备:只能从头开始顺序读写数据,不能指定数据的读写位置
- 随机存储设备:可以定位到任意位置进行数据的读写
打开模式
文件需要指定的打开模式,模式是一个枚举类型,打开模式与**QIODevice::open()**一起使用,描述设备的打开模式
常用(不常用的看ws笔记)的打开模式如下(不是函数没有()):
| 枚举 | 描述 |
|---|---|
| QIODeviceBase::NotOpen | 设备未打开 |
| QIODeviceBase::ReadOnly | 只读 |
| QIODviceBase::WriteOnly | 只写 |
| QIODviceBase::ReadWrite | 读写 |
| QIODeviceBase::Append | 追加 |
| QIODeviceBase::Truncate | 以重写的方式打开,写入新数据会将原数据删除 |
多个模式用|连接
QFile
- QFile可用于读写文本、二进制文件和资源的IO设备。
- QFile可以单独使用,数据通常使用QDataStream或者QTextStream读取和写入,但是也可以使用Qfile继承QDevice的函数read(),readLine(),readAll(),write()......等
- setFileName()设置文件名
- 可以使用exists()检查文件是否存在,并使用remove()删除文件。高级由QFileInfo和QDir提供
- 更详细看另外一个笔记
QFile常用的函数
| 成员方法 | 功能 |
|---|---|
| qint64 QFile::size() const | 获取当前文件的大小,返回字节数 |
| bool QIODevice::getChar(char *c) | 成功true,否则false |
| bool QIODevice::putChar(char c) | 成功true,否则false |
| QByteArray QIODevice::read(qint64 maxSize) | 在文件中读取多少字节的数据 |
| qint64 QIODevice::read(char *data, qint64 maxSize) | 读maxSize到*data中去 |
| QByteArray QIODevice::readAll() | 读取所有数据 |
| qint64 QIODevice::readLine(char *data, qint64 maxSize) | 读取一行 |
| qint64 QIODevice::write(const char *data, qint64 maxSize) | 向data中一次性写入maxSize个字节,返回字节数 |
| qint64 QIODevice::write(const char *data) | 将 data 数据写入文件,该方法返回实际写入的字节数。 |
| qint64 QIODevice::write(const QByteArray &byteArray) | 将 byteArray 数组中存储的字节写入文件,返回实际写入的字节数。 |
| bool QFile::copy(const QString &newName) | 将当前文件的内容拷贝到名为 newName 的文件中,如果成功,方法返回 true,否则返回 false。copy 方法在执行复制操作之前,会关闭源文件。 |
| bool QFile::rename(const QString &newName) | 重命名 |
| bool QFile::remove() | 删除当前文件,成功返回 true,失败返回 false。 |
简单读写
c++
#include <QCoreApplication>
#include<QFile>
#include<QString>
struct Person
{
QString name;
qint8 age;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Person hzeros[]={{"张飞",66},{"关羽",77},{"刘备",99}};
QFile file("text.txt");
if(!file.open(QIODevice::WriteOnly | QIODevice::ReadOnly)){
qWarning()<<file.fileName()<<" 文件打开失败 "<<file.errorString();
return -1;
}
/*
for(int i=0;i<3;i++) {
QString str = QString("name: %1, age: %2\n").arg(hzeros[i].name).arg(hzeros[i].age);
file.write(str.toUtf8());
}
file.close();
*/
QString rstr1 = file.readLine();
//文件指针
file.seek(0);
QString rstr2 = file.readAll();
qDebug()<<rstr1;
qDebug()<<rstr2;
return a.exec();
}
//二进制存储
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
//指定要写入文件的数据
qint32 nums[5]={1,2,3,4,5};
//写入文件之前,要将数据以二进制方式存储到字节数组中
QByteArray byteArr;
byteArr.resize(sizeof(nums));
for(int i=0;i<5;i++){
//借助指针,将每个整数拷贝到字节数组中(用内存拷贝--->二进制)
memcpy(byteArr.data()+i*sizeof(qint32),&(nums[i]),sizeof(qint32));
}
//将 byteArr 字节数组存储到文件中
QFile file("D:/demo.dat");
file.open(QIODevice::WriteOnly);
file.write(byteArr);
file.close();
//再次打开文件,读取文件中存储的二进制数据
file.open(QIODevice::ReadOnly);
QByteArray resArr = file.readAll();
//输出读取到的二进制数据
qDebug()<<"resArr: "<<resArr;
//将二进制数据转化为整数
char* data = resArr.data();
while(*data){
qDebug() << *(qint32*)data;
data += sizeof(qint32);
}
return 0;
}
静态函数
主要作用:文件重命名、复制文件、判断文件是否存在、重置大小......
看另外一篇笔记
Stream
为了简化文本,QT提供了QTextStream和QDataStream辅助类,QTextStream可以将写入的全部数据转化为文本格式,QDataStream可以将数据转化为二进制数据。
学会看文档
QTextStream
学会看文档
c++
class Student
{
public:
qint64 number;
QString name;
QString grade;
qreal math;
qreal chinese;
qreal english;
friend QDebug& operator<<(QDebug& out, const Student& other)
{
out.noquote() << other.number << other.name << other.grade << other.math << other.chinese << other.english;
return out;
}
};
void readStudentInfo()
{
QFile file("./student.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
return -1;
}
Student stu;
QTextStream stream(&file);
qDebug().noquote() <<stream.readLine();
while (!stream.atEnd())
{
stream >> stu.number >> stu.name >> stu.grade >> stu.math >> stu.chinese >> stu.english;
qDebug() << stu;
}
}
void test()
{
QString res;
QTextStream textstream(&res);
textstream << "maye" << QString("冷寂") << "young"; //注意:中文要用Qstirng包起来,否则会乱码
qDebug() <<res;
}
主要方法(注意一下)
| 成员方法 | 功能 |
|---|---|
| bool QTextStream::atEnd() | |
| QString QTextStream::read(qint64 maxlen) | |
| QString QTextStream::readAll() | |
| QString QTextStream::readLine(qint64 maxlen = 0) | |
| void QTextStream::setFieldAlignment(FieldAlignment mode) | 设置对齐方式,通常与 setFieldWidth() 一起使用。 |
| void QTextStream::setFieldWidth(int width) | 设置每份数据占用的位置宽度为 width。 |
QTextStream主要格式
| 描述符 | 功能相同的方法 | 功能 |
|---|---|---|
| Qt::hex | QTextStream::setIntegerBase(16) | 十六进制输出 |
| Qt::showbase | QTextStream::setNumberFlags(numberFlags() ShowBase) | 带上进制前缀 |
| Qt::forcesign | QTextStream::setNumberFlags(numberFlags() ForceSign) | 写入文件的时候带入正负号 |
| Qt::fixed | QTextStream::setRealNumberNotation(FixedNotation) | 将浮点数以小数的方式写入文件 |
| Qt::scientific | QTextStream::setRealNumberNotation(ScientificNotation) | 用科学计数法的方式写入文件 |
| Qt::left | QTextStream::setFieldAlignment(AlignLeft) | 左对齐 |
| Qt::right | QTextStream::setFieldAlignment(AlignRight) | 右对齐 |
| Qt::center | QTextStream::setFieldAlignment(AlignCenter) | 居中对齐 |
c++
#include <QFile>
#include <QDebug>
#include <QString>
#include <QTextStream>
int main(int argc, char *argv[])
{
QFile file("D:/demo.txt");
if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
qDebug()<<"文件打开失败";
}
QTextStream out(&file);
//将 10 的十六进制数写入文件
out << hex << 10;
//设置每份数据占用 10 个字符的位置
out.setFieldWidth(10);
//以右对齐的方式写入 3.14
out << left << 3.14;
//后续数据以左对齐的方式写入文件
out.setFieldAlignment(QTextStream::AlignRight);
out << 2.7;
//关闭文件
file.close();
return 0;
}
QDataStream
二进制流,主要搭配QByteArray
c++
//不只与文件
QByteArray data;
QDataStream stream(&data,QIODevice::ReadWrite); //直接写打开方式
stream << "image" << 1024 << "ABC";
//"[\x00\x00\x00\x06image\x00] [\x00\x00\x04\x00] [\x00\x00\x00\x04" "ABC\x00"] 22
qDebug() << data << data.size();
- bool QDataStream::atEnd() const 判断是否读到文件末尾,如果已经达到末尾,返回 true,否则返回 false。
- QDataStream &QDataStream::readBytes(char *&s, uint &l) 对于用 writeBytes() 方法写入文件的 l 和 s,只能使用 readBytes() 方法读取出来。
- int QDataStream::readRawData(char *s, int len) 从文件中读取最多 len 字节的数据到 s 中,返回值表示实际读取的字节数。注意,调用该方法之前,需要先给 s 参数分配好内存空间。
- void QDataStream::setVersion(int v) 不同版本的 Qt 中,同名称的数据类型也可能存在差异,通过调用此方法手动指定版本号,可以确保读取数据的一致性。
- int QDataStream::skipRawData(int len) 跳过文件中的 len 个字节,返回实际跳过的字节数。
- QDataStream &QDataStream::writeBytes(const char *s, uint len) 将长度 len 和 s 一起写入到文件中,对于 writeBytes() 写入的数据,只能用 readBytes() 方法读取。
- int QDataStream::writeRawData(const char *s, int len) 将 s 中前 len 字节的数据写入文件,返回值表示成功写
配置文件
QSettings
保留信息
创建和初始化
结合另外一篇文章看
常用有两种,其他看文档
C++
//1、使用程序组织名和程序名进行初始化
QSettings settings("OrganizationName","ApplicationName")
//2、配置文件路劲进行初始化
QSettings settings("tett.ini,QSettings::Format::IniFormat());
读写
**注意:**多看文档,当想实现没有函数的时候先去文档看一看
- 组
- 数组
- 文件
c++
//注册表
/*
{
QSettings settings("wyWindowns", qApp->applicationName()); //注意要判断是否成功
settings.setValue("name", "wy");
settings.setValue("age", 18);
}
*/
//ini文件
/*
QSettings setting("./Settings.ini", QSettings::Format::IniFormat); //注意要判断是否成功
setting.setValue("name", "wy");
setting.setValue("age", 18);
//拿到值
qDebug() << setting.value("name").toString() << " " << setting.value("age").toInt();
*/
//创建组
{
QSettings setting("./Settings.ini", QSettings::Format::IniFormat); //注意要判断是否成功
//设置组
setting.beginGroup("Love");
setting.setValue("eat", "eat");
setting.setValue("play", "game");
//读、必须在组里面读
qDebug() << setting.value("eat").toString();
qDebug() << setting.value("eat", "huoguo").toString(); //设置默认值,如果没有则读
setting.endGroup();
}
//数组,看文档
{
QSettings setting("./setting.ini", QSettings::Format::IniFormat);
setting.beginWriteArray("Array");
for (int i = 0; i < 5; i++) {
setting.setArrayIndex(i);
setting.setValue("age", i);
}
setting.endArray(); //一定要关闭
//读
setting.beginReadArray("Array");
for (int i = 0; i < 5; i++) {
setting.setArrayIndex(i);
setting.Value("age").tiInt();
}
setting.endArray(); //一定要关闭
}
//还可以先默认设置程序名字
a.setOrganizationName("WY");
qDebug()<<a.applicationName();
//这样就可以不用指定文件名和程序了
QSettings setting;
应用场景
- 储存应用程序的用户信息
- 状态保存和恢复
- 动态配置调整
- 数据转化,QSettings支持多种数据类型和其转换
JSON
多看文档,文档里面有大量的转换和重载函数
json
#JSON来源于js对象格式
#看另外一篇文档
#数据类型:支持数组、对象、整数、bool、浮点型
#支持{}\[]
#只允许一个置顶{}
#解析json,无论解析数组还是对象,第一步都是先解析json,然后可以通过他的重载[]来获取QJsonValue的值,通过jsonvalue来转换和输出不同值。
解析json
c++
//json文件需要解析,然后在用
QJsonDocument parentJson()
{
QFile file("../bin/text.json");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << file.fileName() << " open failed " << file.errorString();
return {};
}
QJsonParseError jpe;
QJsonDocument jdoc = QJsonDocument::fromJson(file.readAll(), &jpe);
if (jdoc.isNull()) { //判断解析是否失败
qWarning() << "json analysize failed" << jpe.errorString();
}
return jdoc;
}
解析对象
关键:明白json里面数据的结构,一层一层解析
json
{
"maye": {
"age": 18,
"name": "maye",
"tel": "123456789"
},
"yueyue": {
"age": 18,
"name": "yueyue",
"tel": "9987654321"
}
}
c++
//对象读取方法1
qDebug() << jsonDocu["maye"]["age"].toInt() << " " << jsonDocu["maye"]["name"].toString() << " " << jsonDocu["maye"]["tel"].toString();
qDebug() << jsonDocu["yueyue"]["age"].toInt() << " " << jsonDocu["yueyue"]["name"].toString() << " " << jsonDocu["yueyue"]["tel"].toString();
//对象读取方法2,基本原理就是得到键值
/*
auto mayeObj = jsonDocu["maye"].toObject();
qDebug() << mayeObj["age"].toInt();
qDebug() << mayeObj["name"].toString();
qDebug() << mayeObj["tel"].toString();
*/
//对象遍历3,一层一层
auto rootObj = jsonDocu.object(); //获取跟对象,包含json里面的对象
auto keys = rootObj.keys(); //键值是一个集合
for (auto& k : keys) {
auto obj = jsonDocu[k].toObject();
qDebug() << obj.value("age").toInt() << " " << obj["name"].toString();
}
- 法一:用二维数组重载
- 法二:先转换一个对象,然后在解析
- 法三:先将jsonDocu转换成对象(里面包含键值),然后解析对象键值,然后遍历每一个键值
数组
c++
void test_jsonarray()
{
auto jdoc = parseJson("../../../test.json");
if (jdoc.isArray())
{
QJsonArray array = jdoc.array();
for (size_t i = 0; i < array.size(); i++)
{
QJsonValue v = array[i];
if (v.isString())
qDebug() << v.toString();
else if (v.isDouble())
qDebug() << v.toDouble();
else
qDebug() << v;
}
}
}
解析城市json
QDir
QDir类提供对目录结构内容的访问
功能如下(具体函数看文档):
- 对目录进行任意操作(创建、删除、重命名、遍历)
- 能够获取指定目录中的说有条目
- 获取常用路径
c++
//获得目录
QDir dir = QDir("../bin");
if (!dir.exists()) {
qDebug() << dir.dirName() << " open failed ";
return -1;
}
//qstringlist = qlist<qstring>
QStringList dirList = dir.entryList();
for (int i = 0; i < dirList.size(); i++) {
qDebug() << dirList[i];
}
//创建、修改、删除
dir.mkdir("aa");
dir.mkpath("bb/cc/dd/");
dir.rename("aa", "tt");
dir.cd("bb"); //进入bb目录
dir.rename("cc", "ll"); //修改cc
dir.cdUp(); //返回原来目录
dir.rmdir("bb/cc");
dir.rmdir("bb/ll");
dir.rmdir("aa");
dir.rmdir("tt");
//获取项目
QFileInfoList info_list = dir.entryInfoList();
for (auto& k : info_list) {
qDebug() << info_list.size() / 1024 / 1024 << k.fileName() << k.absoluteFilePath();
}
//获取盘符
qDebug() << " --------------------------- ";
QFileInfoList drives = dir.drives();
for (auto& k : drives) {
qDebug() << k.fileName() << k.absoluteFilePath();
}
QDirIterator
主要作用是遍历大文件的(如在C盘下找文件)
c++
//qdiriterator,获取C盘子目录
#if 0
QDirIterator it("C:", QDirIterator::IteratorFlag::Subdirectories);
while (it.hasNext()) {
QString str = it.fileName();
qDebug() << str.toStdString();
it.next();
}
#endif
//在C找mp4格式
QDirIterator it("C:", QDirIterator::IteratorFlag::Subdirectories);
while (it.hasNext()) {
QString str = it.next();
if (str.endsWith(".mp4")) {
qDebug() << str.toStdString();
}
}
QStandardPaths
关于系统标准文件的操作,qt提供了和强大的函数(看文档和另外一篇笔记),可以进行标准文件的查询
c++
//例子:输出标准为文件路径
for (int i = 0; i < 21; i++) {
//standardpaths 是枚举类型,详细看文档
qDebug() << QStandardPaths::StandardLocation(i) << " " << QStandardPaths::standardLocations(QStandardPaths::StandardLocation(i));
}
//找指定路径
qDebug() << QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
QStoragInfo
关于系统磁盘的信息
常用两个静态成员
- root
- mountedVolumes
c++
qDebug() << QStorageInfo::root();
qDebug() << QStorageInfo::mountedVolumes(); //获取所有驱动
磁盘信息在学其他(如linux)关于计算机信息的时候会再次学到