QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)

上篇QT从入门到实战x篇_30_绘图设备(QPixmap、QBitmap、QImage和 QPicture;QPixmap、QBitmap绘制及保存;QImage像素操作;QPicture记录和重现)及之前的博文介绍了绘图事件及设备的相关内容,本篇开始介绍Qt中对文件的操作。

在C和C++中都对文件的读写操作具有一套操作,C中对文件的操作方法参考C语言基础入门48篇_48_文件的写入与读取(fwrite()文件的读取、fread()文件的写入、文件的读取与写入实质即为信息在磁盘与内存直接转换、核心问题:数据在磁盘哪?数据在内存哪?多少数据?),C++中对文件的操作参考C++57个入门知识点_52 cin&cout的奥秘(文件和流;cin是istream的对象,cout是类ostream的对象;endl本质是函数;<<(左移运算符)是一种运算符重载),Qt中对文件的读写操作对应的为 QFile 以及使用 QFileInfo 类来获得文件的信息。

总结:
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第1张图片
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第2张图片

1. 新建工程及场景

  • 新建一个工程
    QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第3张图片
  • 手动创建一个场景
    拖入“Widget”,其中拖入“Line Edit”和“Push Button”,并在拖入的“Widget”中使用水平布局,后在整个的“Widget”中拖入“Text Edit”,整个的“Widget”中使用垂直布局,修改“Push Button”的名字为“选取文件”
    QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第4张图片
    实现在“2”的按钮按下之后,打开地址进行文件的选择,将地址显示在“1”的位置,文件的内容显示在“3”的位置。

2. 文件的读取

2.1 弹出默认路径下的对话框


通过以下代码实现,点击“选取文件”后打开默认地址下的文件

#include "widget.h"
#include "ui_widget.h"
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){
    QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
    });


}

Widget::~Widget()
{
    delete ui;
}

QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第5张图片

2.2 显示地址及内容


下一步实现将读取到的utf-8文件的地址显示在“lineEdit”中,并将内容显示在“textEdit”中
代码如下:

#include "widget.h"
#include "ui_widget.h"
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){

        //返回读取文件的路径地址
        QString path=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //读取内容放入到textEdit中
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

        QByteArray array=file.readAll();

        //将读取到的数据放入到textEdit中
        ui->textEdit->setText(array);
        //对文件进行关闭
        file.close();
    });



}

Widget::~Widget()
{
    delete ui;
}

运行结果如下:
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第6张图片
当我选择同一目录下的“长恨歌_gbk.txt”文件时则会显示为乱码,如下:
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第7张图片
这是因为QFile操作的默认支持的格式为utf-8

2.3 读取非默认格式文件


可以通过 编码格式类来读取 “gbk”等非默认的文件

代码如下:

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){

        //返回读取文件的路径地址
        QString path=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //编码格式类,写出支持的格式的name,相当于指定了codec的格式为gbk格式
        QTextCodec* codec=QTextCodec::codecForName("gbk");

        //读取内容放入到textEdit中
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

        QByteArray array=file.readAll();

        //将读取到的数据放入到textEdit中
//        ui->textEdit->setText(array);

        //将array中的内容转换为codec指定的格式
        ui->textEdit->setText(codec->toUnicode(array));
        //对文件进行关闭
        file.close();
    });

}

Widget::~Widget()
{
    delete ui;
}

此时就可以打开“gbk”文件,但是同时无法打开utf-8格式的文件,这可以在网上找相关的案例,先判断文件第一个字符是“gbk”还是“utf-8”格式,然后根据不同的格式读取数据。

后边还是采用默认格式文件的读取进行演示

2.4 按行读取文件


上面的操作时一次性将所有内容读出,也可以一行行的读取文件内容,以下代码实现按行读取完文件所有内容并进行显示。

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){

        //返回读取文件的路径地址
        QString path=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //编码格式类,写出支持的格式的name,相当于指定了codec的格式为gbk格式
//        QTextCodec* codec=QTextCodec::codecForName("gbk");

        //读取内容放入到textEdit中
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

//        QByteArray array=file.readAll();

        QByteArray array;

        while(!file.atEnd())
        {
            array+=file.readLine(); //按行读
        }

        //将读取到的数据放入到textEdit中
        ui->textEdit->setText(array);

//        //将array中的内容转换为codec指定的格式
//        ui->textEdit->setText(codec->toUnicode(array));

        //对文件进行关闭
        file.close();
    });
}

Widget::~Widget()
{
    delete ui;
}

3. 文件写操作


以上是对文件进行了读的操作,以下进行写的操作

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){

        //返回读取文件的路径地址
        QString path=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //编码格式类,写出支持的格式的name,相当于指定了codec的格式为gbk格式
//        QTextCodec* codec=QTextCodec::codecForName("gbk");

        //读取内容放入到textEdit中
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

//        QByteArray array=file.readAll();

        QByteArray array;

        while(!file.atEnd())
        {
            array+=file.readLine(); //按行读
        }

        //将读取到的数据放入到textEdit中
        ui->textEdit->setText(array);

//        //将array中的内容转换为codec指定的格式
//        ui->textEdit->setText(codec->toUnicode(array));

        //对文件进行关闭
        file.close();

        //进行写操作
        file.open(QIODevice::Append); //用追加的方式进行写
        file.write("123");
        file.close();

    });

}

Widget::~Widget()
{
    delete ui;
}

运行结果如下:
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第8张图片

4. QFileInfo实现基本文件信息读取


使用QFileInfo类可以获得文件创建时间、修改时间、后缀名、文件长度等相关信息,具体代码如下:

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 
#include 
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击文件选取按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){

        //返回读取文件的路径地址
        QString path=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开文件"),"D:\\SelfProgram\\QTTest\\Qt3_Day26\\Code\\05_Qt_QFile");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //编码格式类,写出支持的格式的name,相当于指定了codec的格式为gbk格式
//        QTextCodec* codec=QTextCodec::codecForName("gbk");

        //读取内容放入到textEdit中
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

//        QByteArray array=file.readAll();

        QByteArray array;

        while(!file.atEnd())
        {
            array+=file.readLine(); //按行读
        }

        //将读取到的数据放入到textEdit中
        ui->textEdit->setText(array);

//        //将array中的内容转换为codec指定的格式
//        ui->textEdit->setText(codec->toUnicode(array));

        //对文件进行关闭
        file.close();

        //进行写操作
//        file.open(QIODevice::Append); //用追加的方式进行写
//        file.write("123");
//        file.close();

     //QFileInfo 文件信息类
        QFileInfo info(path);
        qDebug()<<QString::fromLocal8Bit("大小:")<<info.size()<<QString::fromLocal8Bit("后缀名:")<<info.suffix()<<QString::fromLocal8Bit("文件名称:")<<info.fileName()<<QString::fromLocal8Bit("文件路径:")<<info.filePath();
        qDebug()<<QString::fromLocal8Bit("创建日期:")<<info.created().toString("yyyy/MM/dd hh:mm:ss");
        qDebug()<<QString::fromLocal8Bit("最后修改日期:")<<info.lastModified().toString("yyyy-MM-dd hh:mm:ss");
    });

}

Widget::~Widget()
{
    delete ui;
}

运行结果:
QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第9张图片

5. 学习视频地址:QFile文件读写操作(QFile进行基本文件操作,file.open;file.readAll;file.write;file.close;二进制文件读写;文本文件读写),QFileInfo基本文件信息读取

以下为Qt中文件系统的笔记:

11 文件系统
文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库,提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象,这些设备具有读写字节块的能力。下面是 I/O 设备的类图(Qt5):

QT从入门到实战x篇_31_QFile文件读写操作&QFileInfo实现基本文件信息读取(QFile进行基本文件操作;二进制文件读写;文本文件读写)_第10张图片

	QIODevice:所有 I/O 设备类的父类,提供了字节块读写的通用操作以及基本接口;
	QFileDevice:Qt5新增加的类,提供了有关文件操作的通用实现。
	QFlie:访问本地文件或者嵌入资源;
	QTemporaryFile:创建和访问本地文件系统的临时文件;
	QBuffer:读写QbyteArray, 内存文件;
	QProcess:运行外部程序,处理进程间通讯;
	QAbstractSocket:所有套接字类的父类;
	QTcpSocket:TCP协议网络数据传输;
	QUdpSocket:传输 UDP 报文;
	QSslSocket:使用 SSL/TLS 传输数据;
文件系统分类:
	顺序访问设备:
是指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节,这其中,QProcess、QTcpSocket、QUdpSoctet和QSslSocket是顺序访问设备。
	随机访问设备:
可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针,QFile、QTemporaryFile和QBuffer是随机访问设备, 
11.1 基本文件操作
文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库,提供了跨平台的文件操作能力。在所有的 I/O 设备中,文件 I/O 是最重要的部分之一。因为我们大多数的程序依旧需要首先访问本地文件(当然,在云计算大行其道的将来,这一观点可能改变)。QFile提供了从文件中读取和写入数据的能力。
我们通常会将文件路径作为参数传给QFile的构造函数。不过也可以在创建好对象最后,使用setFileName()来修改。QFile需要使用 / 作为文件分隔符,不过,它会自动将其转换成操作系统所需要的形式。例如 C:/windows 这样的路径在 Windows 平台下同样是可以的。
QFile主要提供了有关文件的各种操作,比如打开文件、关闭文件、刷新文件等。我们可以使用QDataStream或QTextStream类来读写文件,也可以使用QIODevice类提供的read()readLine()readAll()以及write()这样的函数。值得注意的是,有关文件本身的信息,比如文件名、文件所在目录的名字等,则是通过QFileInfo获取,而不是自己分析文件路径字符串。
下面我们使用一段代码来看看QFile的有关操作:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QFile file("in.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Open file failed.";
        return -1;
    } else {
        while (!file.atEnd()) {
            qDebug() << file.readLine();
        }
    }
 
    QFileInfo info(file);
    qDebug() << info.isDir();
    qDebug() << info.isExecutable();
    qDebug() << info.baseName();
    qDebug() << info.completeBaseName();
    qDebug() << info.suffix();
    qDebug() << info.completeSuffix();
 
    return app.exec();
}
	我们首先使用QFile创建了一个文件对象。
这个文件名字是 in.txt。如果你不知道应该把它放在哪里,可以使用QDir::currentPath()来获得应用程序执行时的当前路径。只要将这个文件放在与当前路径一致的目录下即可。
	使用open()函数打开这个文件,打开形式是只读方式,文本格式。
这个类似于fopen()的 r 这样的参数。open()函数返回一个 bool 类型,如果打开失败,我们在控制台输出一段提示然后程序退出。否则,我们利用 while 循环,将每一行读到的内容输出。
	可以使用QFileInfo获取有关该文件的信息。
QFileInfo有很多类型的函数,我们只举出一些例子。比如:
	isDir()检查该文件是否是目录;
	isExecutable()	检查该文件是否是可执行文件等。
	baseName()		可以直接获得文件名;
	completeBaseName() 	获取完整的文件名
	suffix()	则直接获取文件后缀名。
	completeSuffix() 	获取完整的文件后缀
我们可以由下面的示例看到,baseName()completeBaseName(),以及suffix()completeSuffix()的区别:
QFileInfo fi("/tmp/archive.tar.gz");
QString base  = fi.baseName();  // base = "archive"
QString base  = fi.completeBaseName();  // base = "archive.tar"
QString ext   = fi.suffix();  // ext = "gz"
QString ext   = fi.completeSuffix();  // ext = "tar.gz"
11.2 二进制文件读写
QDataStream提供了基于QIODevice的二进制数据的序列化。数据流是一种二进制流,这种流完全不依赖于底层操作系统、CPU 或者字节顺序(大端或小端)。例如,在安装了 Windows 平台的 PC 上面写入的一个数据流,可以不经过任何处理,直接拿到运行了 Solaris 的 SPARC 机器上读取。由于数据流就是二进制流,因此我们也可以直接读写没有编码的二进制数据,例如图像、视频、音频等。
QDataStream既能够存取 C++ 基本类型,如 intcharshort 等,也可以存取复杂的数据类型,例如自定义的类。实际上,QDataStream对于类的存储,是将复杂的类分割为很多基本单元实现的。
结合QIODevice,QDataStream可以很方便地对文件、网络套接字等进行读写操作。我们从代码开始看起:
QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << QString("the answer is");
out << (qint32)42;
	在这段代码中,我们首先打开一个名为 file.dat 的文件(注意,我们为简单起见,并没有检查文件打开是否成功,这在正式程序中是不允许的)。然后,我们将刚刚创建的file对象的指针传递给一个QDataStream实例out。类似于std::cout标准输出流,QDataStream也重载了输出重定向<<运算符。后面的代码就很简单了:将“the answer is”和数字 42 输出到数据流。由于我们的 out 对象建立在file之上,因此相当于将问题和答案写入file。
	需要指出一点:最好使用 Qt 整型来进行读写,比如程序中的qint32。这保证了在任意平台和任意编译器都能够有相同的行为。
如果你直接运行这段代码,你会得到一个空白的 file.dat,并没有写入任何数据。这是因为我们的file没有正常关闭。为性能起见,数据只有在文件关闭时才会真正写入。因此,我们必须在最后添加一行代码:
file.close(); // 如果不想关闭文件,可以使用 file.flush();
接下来我们将存储到文件中的答案取出来
QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QString str;
qint32 a;
in >> str >> a;
唯一需要注意的是,你必须按照写入的顺序,将数据读取出来。顺序颠倒的话,程序行为是不确定的,严重时会直接造成程序崩溃。
那么,既然QIODevice提供了read()readLine()之类的函数,为什么还要有QDataStream呢?QDataStream同QIODevice有什么区别?区别在于,QDataStream提供流的形式,性能上一般比直接调用原始 API 更好一些。我们通过下面一段代码看看什么是流的形式:
QFile file("file.dat");
file.open(QIODevice::ReadWrite);
 
QDataStream stream(&file);
QString str = "the answer is 42";

stream << str;
11.3 文本文件读写
上一节我们介绍了有关二进制文件的读写。二进制文件比较小巧,却不是人可读的格式。而文本文件是一种人可读的文件。为了操作这种文件,我们需要使用QTextStream类。QTextStream和QDataStream的使用类似,只不过它是操作纯文本文件的。
QTextStream会自动将 Unicode 编码同操作系统的编码进行转换,这一操作对开发人员是透明的。它也会将换行符进行转换,同样不需要自己处理。QTextStream使用 16 位的QChar作为基础的数据存储单位,同样,它也支持 C++ 标准类型,如 int 等。实际上,这是将这种标准类型与字符串进行了相互转换。
QTextStream同QDataStream的使用基本一致,例如下面的代码将把“The answer is 42”写入到 file.txt 文件中:
QFile data("file.txt");
if (data.open(QFile::WriteOnly | QIODevice::Truncate)) 
{
    QTextStream out(&data);
    out << "The answer is " << 42;
}
这里,我们在open()函数中增加了QIODevice::Truncate打开方式。我们可以从下表中看到这些打开方式的区别:
枚举值	               描述
	QIODevice::NotOpen		未打开
	QIODevice::ReadOnly		以只读方式打开
	QIODevice::WriteOnly		以只写方式打开
	QIODevice::ReadWrite		以读写方式打开
	QIODevice::Append			以追加的方式打开,
新增加的内容将被追加到文件末尾
	QIODevice::Truncate		以重写的方式打开,在写入新的数据时会将原有
							数据全部清除,游标设置在文件开头。
	QIODevice::Text			在读取时,将行结束符转换成 \n;在写入时,
将行结束符转换成本地格式,例如 Win32 平台
上是 \r\n
	QIODevice::Unbuffered	忽略缓存
我们在这里使用了QFile::WriteOnly | QIODevice::Truncate,也就是以只写并且覆盖已有内容的形式操作文件。注意,QIODevice::Truncate会直接将文件内容清空。

虽然QTextStream的写入内容与QDataStream一致,但是读取时却会有些困难:
QFile data("file.txt");
if (data.open(QFile::ReadOnly)) 
{
    QTextStream in(&data);
    QString str;
    int ans = 0;
    in >> str >> ans;
}
在使用QDataStream的时候,这样的代码很方便,但是使用了QTextStream时却有所不同:读出的时候,str 里面将是 The answer is 42,ans 是 0。这是因为当使用QDataStream写入的时候,实际上会在要写入的内容前面,额外添加一个这段内容的长度值。而以文本形式写入数据,是没有数据之间的分隔的。因此,使用文本文件时,很少会将其分割开来读取,而是使用诸如使用:
	QTextStream::readLine()	读取一行
	QTextStream::readAll()读取所有文本
这种函数之后再对获得的QString对象进行处理。
默认情况下,QTextStream的编码格式是 Unicode,如果我们需要使用另外的编码,可以使用:
stream.setCodec("UTF-8");
这样的函数进行设置。

你可能感兴趣的:(#,QT从入门到实战x篇,qt,c++,开发语言)