【QT】--文件操作


前言

  • 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)关于计算机信息的时候会再次学到

相关推荐
2501_940315262 小时前
【无标题】1.17给定一个数将其转换为任意一个进制数(用栈的方法)
开发语言·c++·算法
张彦峰ZYF2 小时前
商品供给域的工程化简要设计考量
后端·系统架构·商品模型·商品供给
coding-fun2 小时前
电子发票批量提取导出合并助手
大数据·数据库
leo_2322 小时前
备份&恢复--SMP(软件制作平台)语言基础知识之三十九
数据库·数据安全·开发工具·smp(软件制作平台)·应用系统
何以不说话2 小时前
mysql 的主从复制
运维·数据库·学习·mysql
二二牧人2 小时前
qemu arm64 linux开发环境搭建
linux·运维·数据库
fpcc2 小时前
C++23中的模块应用说明之五综合应用和重点分
c++·c++23
茁壮成长的露露3 小时前
导出导入工具mongoexport、mongoimport
数据库·mongodb
晚风资源组3 小时前
CSS文字和图片在容器内垂直居中的简单方法
前端·css·css3