• Qt QFile文件操作详解


    文件操作是非常重要的,是数据持久化的方法。通过文件操作,我们可以把在软件中设置的数据保存起来。

    已剪辑自: http://c.biancheng.net/view/vip_9663.html

    很多应用程序都需要具备操作文件的能力,包括对文件内容进行读/写、创建和删除文件等,甚至某些应用程序的诞生纯粹是为了操作文件,比如 WPS Office、PDFedit 等。为此,Qt 框架提供了 QFile 类专门用来操作文件。

    QFile文件操作

    QFile 类支持对文件进行读取、写入、删除、重命名、拷贝等操作,它既可以操作文件文件,也可以操作二进制文件。

    使用 QFile 类操作文件之前,程序中需引入头文件。创建 QFile 类的对象,常用的构造函数有:

    QFile::QFile()
    QFile::QFile(const QString &name)
    
    • 1
    • 2

    参数 name 用来指定要操作的目标文件,包含文件的存储路径和文件名,存储路径可以使用绝对路径(比如 “D:/Demo/test.txt”)或者相对路径(比如"./Demo/test.txt"),路径中的分隔符要用 “/” 表示。

    通常情况下,我们会调用第二个构造函数,直接指明要操作的文件。对于第一个构造函数创建的 QFile 对象,需要再调用 setFileName() 方法指明要操作的文件。

    与 C++ 读写文件的规则一样,使用 QFile 读写文件之前必须先打开文件,调用 open() 成员方法即可,常用的语法格式为:

    bool QFile::open(OpenMode mode)
    
    • 1

    mode 参数用来指定文件的打开方式,下表罗列了此参数的可选值以及各自的含义:

    表 1 QFile文件打开方式 打开方式 含 义

    QIODevice::ReadOnly只能对文件进行读操作
    QIODevice::WriteOnly只能对文件进行写操作,如果目标文件不存在,会自行创建一个新文件。
    QIODevice::ReadWrite等价于 ReadOnly | WriteOnly,能对文件进行读和写操作。
    QIODevice::Append以追加模式打开文件,写入的数据会追加到文件的末尾(文件原有的内容保留)。
    QIODevice::Truncate以重写模式打开,写入的数据会将原有数据全部清除。注意,此打开方式不能单独使用,通常会和 ReadOnly 或 WriteOnly 搭配。
    QIODevice::Text读取文件时,会将行尾结束符(Unix 系统中是 “\n”,Windows 系统中是 “\r\n”)转换成‘\n’;将数据写入文件时,会将行尾结束符转换成本地格式,例如 Win32 平台上是‘\r\n’。

    根据需要,可以为 mode 参数一次性指定多个值,值和值之间用|分割。比如:

    • QIODevice::ReadOnly | QIODevice::Text:表示只允许对文件进行读操作,读取文件时,会将行尾结束符转换为 ‘\n’;
    • QIODevice::WriteOnly | QIODevice::Text:表示只允许对文件进行写操作,将数据写入文件时,会将行尾结束符转换为本地格式;
    • QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text:表示对文件进行写操作,写入的数据会存放到文件的尾部,同时数据中的行尾结束符转换为本地格式。

    注意,传递给 mode 参数的多个值之间不能相互冲突,比如 Append 和 Truncate 不能同时使用。

    如果文件成功打开,open() 函数返回 true,否则返回 false。

    QFile 类提供了很多功能实用的方法,可以快速完成对文件的操作,下表列举了常用的一些:

    表 2 QFile常用方法 普通成员方法 功 能

    qint64 QFile::size() const获取当前文件的大小。对于打开的文件,该方法返回文件中可以读取的字节数。
    bool QIODevice::getChar(char *c)从文件中读取一个字符,并存储到 c 中。读取成功时,方法返回 true,否则返回 false。
    bool QIODevice::putChar(char c)向文件中写入字符 c,成功时返回 true,否则返回 false。
    QByteArray QIODevice::read(qint64 maxSize)从文件中一次性最多读取 maxSize 个字节,然后返回读取到的字节。
    qint64 QIODevice::read(char *data, qint64 maxSize)从文件中一次性对多读取 maxSize 个字节,读取到的字节存储到 data 指针指定的内存控件中。该方法返回成功读取到的字节数。
    QByteArray QIODevice::readAll()读取文件中所有的数据。
    qint64 QIODevice::readLine(char *data, qint64 maxSize)每次从文件中读取一行数据或者读取最多 maxSize-1 个字节,存储到 data 中。该方法返回实际读取到的字节数。
    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)对当前文件进行重命名,新名称为 newName,成功返回 true,失败返回 false。
    bool QFile::remove()删除当前文件,成功返回 true,失败返回 false。

    【实例一】演示了 QFile 类读写文本文件的过程。

    #include 
    #include 
    int main(int argc, char *argv[])
    {
        //创建 QFile 对象,同时指定要操作的文件
        QFile file("D:/demo.txt");
        //对文件进行写操作
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            qDebug()<<"文件打开失败";
        }
        //向文件中写入两行字符串
        file.write("C语言中文网\n");
        file.write("http://c.biancheng.net");
        //关闭文件
        file.close();
        //重新打开文件,对文件进行读操作
        if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
            qDebug()<<"文件打开失败";
        }
        //每次都去文件中的一行,然后输出读取到的字符串
        char * str = new char[100];
        qint64 readNum = file.readLine(str,100);
        //当读取出现错误(返回 -1)或者读取到的字符数为 0 时,结束读取
        while((readNum !=0) && (readNum != -1)){
            qDebug() << str;
            readNum = file.readLine(str,100);
        }
        file.close();
        return 0;
    }
    
    • 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

    执行程序,“C语言中文网” 和 “http://c.biancheng.net” 先写入 D 盘的 demo.txt 文件,然后再从文件中将它们读取出来。

    【实例二】演示 QFile 读写二进制文件的过程。

    #include 
    #include 
    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;
    }
    
    • 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

    执行程序,demo.dat 文件中会存储 {1,2,3,4,5} 这 5 个整数的二进制形式,同时输出以下内容:

    resArr: “\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00”
    1
    2
    3
    4
    5

    单独使用 QFile 类读写文件的过程既繁琐又复杂,Qt 提供了两个辅助类 QTextStream 和 QDataStream,前者用来读写文件文件,后者用来读写二进制文件,QFile 可以和它们搭配使用,从整体上提高读写文件的开发效率。

    QFile+QTextStream

    和单独使用 QFile 类读写文本文件相比,QTextStream 类提供了很多读写文件相关的方法,还可以设定写入到文件中的数据格式,比如对齐方式、写入数字是否带前缀等等。

    使用 QTextStream 类之前,程序中要先引入头文件。QTextStream 类提供了很多种构造函数,常用的是:

    QTextStream(QIODevice *device)
    
    • 1

    QIODevice 是 QFile 的父类,因此在构造 QTextStream 类的对象时,需要传递一个 QFile 类的对象。

    下表罗列了 QTextStream 类常用的一些方法:
    表 3 QTextStream常用方法 成员方法 功 能

    bool QTextStream::atEnd() const判断是否读到文件末尾,如果已经达到末尾,返回 true,否则返回 false。
    QString QTextStream::read(qint64 maxlen)从文件中读最多 maxlen 个字符,返回这些字符组成的 QString 字符串。
    QString QTextStream::readAll()从文件中读取所有内容,返回由读取内容组成的 QString 字符串。
    QString QTextStream::readLine(qint64 maxlen = 0)默认读取一行文本,如果手动指定 maxlen 的值,则最多读取 maxlen 个字符,并返回读取内容组成的 QString 字符串。
    void QTextStream::setFieldAlignment(FieldAlignment mode)设置对齐方式,通常与 setFieldWidth() 一起使用。
    void QTextStream::setFieldWidth(int width)设置每份数据占用的位置宽度为 width。

    QTextStream 类重载了>>输入运算符和>>输出运算符,使读写文本文件变得更简单。例如,用 QTextStream 实现【实例一】的程序如下:

    #include 
    #include 
    #include 
    #include 
    int main(int argc, char *argv[])
    {
        //创建 QFile 对象,同时指定要操作的文件
        QFile file("D:/demo.txt");
        //对文件进行写操作
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            qDebug()<<"文件打开失败";
        }
        QTextStream out(&file);
        //向文件中写入两行字符串
        out << (QString)"C语言中文网\n" << (QString)"http://c.biancheng.net";
        //关闭文件
        file.close();
        //重新打开文件,对文件进行读操作
        if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
            qDebug()<<"文件打开失败";
        }
        QTextStream in(&file);
        //一直读,直至读取失败
        while(!in.atEnd()){
            QString str;
            //从文件中读取一个字符串
            in >> str;
            qDebug() << str;
        }
        file.close();
        return 0;
    }
    
    • 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

    类似,QTextStream 类提供了两种格式化输出的方法,一种是调用该类的成员方法,例如表 3 中的 setFieldAlignment()、setFieldWidth 等,另一种是调用 QTextStream 类提供的格式描述符,下表罗列了常用的一些:

    表 4 QTextStream常用格式描述符 描述符 功能相同的方法 功 能

    Qt::hexQTextStream::setIntegerBase(16)将指定整数对应的 16 进制数写入到文件中。
    Qt::showbaseQTextStream::setNumberFlags(numberFlags() | ShowBase)对于非十进制数,写入到文件中时带上相应的前缀。二进制数前缀是 0b,八进制数前缀是 0,十六进制数前缀是 0x。
    Qt::forcesignQTextStream::setNumberFlags(numberFlags() | ForceSign)将数字写入文件时,带上正负号。
    Qt::fixedQTextStream::setRealNumberNotation(FixedNotation)将浮点数以普通小数的形式写入文件。
    Qt::scientificQTextStream::setRealNumberNotation(ScientificNotation)将浮点数以科学计数法的形式写入文件。
    Qt::leftQTextStream::setFieldAlignment(AlignLeft)左对齐
    Qt::rightQTextStream::setFieldAlignment(AlignRight)右对齐
    Qt::centerQTextStream::setFieldAlignment(AlignCenter)居中对齐

    举个简单的例子:

    #include 
    #include 
    #include 
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    程序运行后,demo.txt 存储的文本内容为:

    a3.14 2.7

    QFile+QDataStream

    QDataStream 类的用法和 QTextStream 非常类似,最主要的区别在于,QDataStream 用于读写二进制文件。

    使用 QDataStream 类之前,程序中要引入头文件。创建 QDataStream 对象常用的构造函数为:

    QDataStream::QDataStream(QIODevice *d)
    
    • 1

    下表罗列了 QDataStream 类常用的成员方法:
    表 5 QDataStream常用方法 成员方法 功 能

    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 字节的数据写入文件,返回值表示成功写入的字节数。

    QDataStream 类也对<<>>进行了重载,举个简单的例子,用 QDataStream 重新实现实例二:

    #include 
    #include 
    #include 
    int main(int argc, char *argv[])
    {
        //指定要写入文件的数据
        qint32 nums[5]={1,2,3,4,5};
        QFile file("D:/demo.dat");
        file.open(QIODevice::WriteOnly);
        //创建 QDataStream 对象
        QDataStream out(&file);
        //将 nums 数组中的整数逐个写入到二进制文件中
        for(int i=0;i<5;i++){
          out << nums[i];
        }
        file.close();
        //再次打开文件,读取文件中存储的二进制数据
        file.open(QIODevice::ReadOnly);
        QDataStream in(&file);
        //读取二进制文件中的数据
        while(!in.atEnd()){
            //每次读取一个整数
            qint32 num;
            in >> num;
            qDebug() << num;
        }
        return 0;
    }
    
    • 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

    输出结果为:

    1
    2
    3
    4
    5

  • 相关阅读:
    c# 输出二进制字符串
    人工智能AI界的龙头企业,炸裂的“英伟达”时代能走多远
    js 不同域iframe 与父页面消息通信
    c++ 智能指针 shared_ptr
    构筑智算未来,九州未来受邀出席首都学术资源开放共享沙龙
    oracle中创建自动增长列
    【kafka】Java客户端代码demo:自动异步提交、手动同步提交及提交颗粒度、动态负载均衡
    二叉搜索树的最近公共祖先
    [树学习]-二叉搜索树
    Android 13 - Media框架(14)- OpenMax(二)
  • 原文地址:https://blog.csdn.net/qq_41854911/article/details/128048134