文件的读写应用场景十分广泛,也是我们必须要学习的。以下是Qt中,文件系统的结构图:
文件系统结构图
文件的读写在网络编程中很常用,必须要拿下QAQ
QFile读文件
读取文件的步骤:获取文件路径→创建文件并指定路径→打开文件→读取文本→用户自定义操作→关闭文件。
//Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#pragma execution_character_set("utf-8")
#include <QWidget>
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void Widget::openFile();
public:
QGridLayout *layout=new QGridLayout(this);
QPushButton *b1=new QPushButton(this);
QPushButton *b2=new QPushButton(this);
QTextEdit *editor=new QTextEdit(this);
};
#endif // WIDGET_H
复制代码
//Widget.cpp
#include "Widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QFileDialog>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
b1->setText("读取文本");
b2->setText("写入文本");
layout->addWidget(b1,0,0,1,1);
layout->addWidget(b2,0,1,1,1);
layout->addWidget(editor,1,0,1,2);
this->setLayout(layout);
this->resize(300,400);
connect(b1,&QPushButton::clicked,this,&Widget::openFile);
}
Widget::~Widget()
{
}
void Widget::openFile(){
//生成一个文件对话框并获取文件路径
QString path=QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop","text(*.txt)");
if(!path.isEmpty()){ //若文件路径不为空
//创建QFile对象并指定路径
QFile file(path);
//一定要记得打开文件,并设置读写模式
file.open(QIODevice::ReadOnly);
//读取文件内容,一次性全部读入并保存在字节数组对象array中,默认只识别UTF-8编码的文件,其余编码格式会产生乱码
QByteArray array=file.readAll();
//将读取到的文本内容显示在文本编辑框中
this->editor->setText(array);
//记得关闭文件
file.close();
}
}
复制代码
实现效果:
如果不想一次性读入所有文本,而是想要逐行读取,可以这样来实现:
#include "Widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QFileDialog>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
b1->setText("读取文本");
b2->setText("写入文本");
layout->addWidget(b1,0,0,1,1);
layout->addWidget(b2,0,1,1,1);
layout->addWidget(editor,1,0,1,2);
this->setLayout(layout);
this->resize(300,400);
connect(b1,&QPushButton::clicked,this,&Widget::openFile);
}
Widget::~Widget()
{
}
void Widget::openFile(){
//生成一个文件对话框并获取文件路径
QString path=QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop","text(*.txt)");
if(!path.isEmpty()){ //若文件路径不为空
//创建QFile对象并指定路径
QFile file(path);
//一定要记得打开文件,并设置读写模式
file.open(QIODevice::ReadOnly);
//读取文件内容,一次性全部读入并保存在字节数组对象array中,默认只识别UTF-8编码的文件,其余编码格式会产生乱码
QByteArray array;
//若文件未达到结尾
while(!file.atEnd()){
//逐行读取并拼接到字节数组array中
array+=file.readLine();
}
//将读取到的文本内容显示在文本编辑框中
this->editor->setText(array);
//记得关闭文件
file.close();
}
}
复制代码
实现效果是一模一样的:
(只是在趁机安利Jay的乱舞春秋(◔v◔)
QFile写文件
回想在我们的日常操作中,写文件的步骤也是先对文本进行编辑,接着打开一个文件对话框,再选择要保存的路径,其实与读文件的实现方法差不多:
#ifndef WIDGET_H
#define WIDGET_H
#pragma execution_character_set("utf-8")
#include <QWidget>
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void Widget::openFile();
void Widget::saveFile();
public:
QGridLayout *layout=new QGridLayout(this);
QPushButton *b1=new QPushButton(this);
QPushButton *b2=new QPushButton(this);
QTextEdit *editor=new QTextEdit(this);
};
#endif // WIDGET_H
复制代码
//Widget.cpp
#include "Widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QFileDialog>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
b1->setText("读取文本");
b2->setText("写入文本");
layout->addWidget(b1,0,0,1,1);
layout->addWidget(b2,0,1,1,1);
layout->addWidget(editor,1,0,1,2);
this->setLayout(layout);
this->resize(300,400);
connect(b1,&QPushButton::clicked,this,&Widget::openFile);
connect(b2,&QPushButton::clicked,this,&Widget::saveFile);
}
Widget::~Widget()
{
}
void Widget::openFile(){
//生成一个文件对话框并获取文件路径
QString path=QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop","text(*.txt)");
if(!path.isEmpty()){ //若文件路径不为空
//创建QFile对象并指定路径
QFile file(path);
//一定要记得打开文件,并设置读写模式
file.open(QIODevice::ReadOnly);
//读取文件内容,一次性全部读入并保存在字节数组对象array中,默认只识别UTF-8编码的文件,其余编码格式会产生乱码
QByteArray array=file.readAll();
//将读取到的文本内容显示在文本编辑框中
this->editor->setText(array);
//记得关闭文件
file.close();
}
}
void Widget::saveFile(){
//获取文本编辑框的内容并转化为QString对象
QString text=this->editor->toPlainText();
//打开一个文件对话框并获取保存文件的路径
QString path=QFileDialog::getSaveFileName(this,"save","C:/Users/MSI-NB/Desktop","text(*.txt)");
//创建一个文件对象,并关联路径
QFile file;
file.setFileName(path);
//打开文件
file.open(QIODevice::WriteOnly);
//往文件中写入文本
file.write(text.toUtf8());
//记得关闭文件
file.close();
}
复制代码
实现效果:
首先,我打开原来的歌词文件,在文本编辑区域修改了一句歌词,接着点击“写入文本”按钮,指定文件保存的路径(这里我没有新建一个文件,而是直接覆盖了原来的文件),然后再点击“读取文本”,读取出刚刚保存的文件,发现歌词已经被成功修改了。
说明:
在读取文本框内容的时候,我们调用了toPlainText()
方法将文本转化为QString类型的字符串,但是要调用write()
方法往文件中写入时,需要以QByteArray字节数组的形式,因此还需要调用toUtf8()
方法将QString类型的字符串进行转化。
在这里补充几个Qt中常用的不同类型的文本流之间转化的方法:
QString → QByteArray:
QByteArray array=str.toUft8(); //str是QString对象
复制代码
QString对象不仅可以转化为UTF-8编码的字节数组,还可以转化为其它方式编码的字节数组,比如使用本地平台编码方式:
QByteString array=str.toLocal8Bit();
复制代码
QString → std::string(C++标准字符串) → char *:
qDebug()<<"typing "<<str.toStdString().data(); //text是QString对象
复制代码
QByteArray → char *:
char *b=array.data(); //array是QByteArray对象
复制代码
char * → QString:
char *p="abc";
QString str=QString(p);
复制代码
#include "Widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QFileDialog>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
b1->setText("读取文本");
b2->setText("写入文本");
layout->addWidget(b1,0,0,1,1);
layout->addWidget(b2,0,1,1,1);
layout->addWidget(editor,1,0,1,2);
this->setLayout(layout);
this->resize(300,400);
connect(b1,&QPushButton::clicked,this,&Widget::openFile);
connect(b2,&QPushButton::clicked,this,&Widget::saveFile);
}
Widget::~Widget()
{
}
void Widget::openFile(){
//生成一个文件对话框并获取文件路径
QString path=QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop","text(*.txt)");
if(!path.isEmpty()){ //若文件路径不为空
//创建QFile对象并指定路径
QFile file(path);
//一定要记得打开文件,并设置读写模式
file.open(QIODevice::ReadOnly);
//读取文件内容,一次性全部读入并保存在字节数组对象array中,默认只识别UTF-8编码的文件,其余编码格式会产生乱码
QByteArray array=file.readAll();
//将读取到的文本内容显示在文本编辑框中
this->editor->setText(array);
//记得关闭文件
file.close();
}
}
void Widget::saveFile(){
//获取文本编辑框的内容并转化为QString对象
QString text=this->editor->toPlainText();
//打开一个文件对话框并获取保存文件的路径
QString path=QFileDialog::getSaveFileName(this,"save","C:/Users/MSI-NB/Desktop","text(*.txt)");
//创建一个文件对象,并关联路径
QFile file;
file.setFileName(path);
//打开文件
file.open(QIODevice::WriteOnly);
file.write(text.toUtf8());
QByteArray qba=text.toUtf8(); //先将QString转化为QByteArray,采用UTF-8编码
char *b=qba.data(); //再将QByteArray转化为char *
qDebug()<<"typing "<<qba; //打印QByteArray
qDebug()<<"typing "<<b; //打印char *
//关闭文件
file.close();
}
复制代码
实现效果:
输入英文,调用toUtf8()后得到的QByteArray对象与调用toUtf8().data()后得到的char * 变量的区别在于,前者多了双引号。
输入中文,调用toUtf8()后得到的QByteArray对象与调用toUtf8().data()后得到的char * 变量的区别除了前者多了双引号之外,输出char * 变量可以得到完整的中文字符串将字符串,而输出QByteArray对象得到的是一些UTF-8表示形式。
注意:如果需要输出中文,应该先用toUtf8()
方法转化成Unicode编码,再用data()
方法转化成我们可以识别的中文字符串。
QFileInfo获取文件信息
文件自身携带一些信息,如文件大小、创建时间、后缀名等等,要获取这些信息,需要用到QFileInfo。使用QFileInfo需要先引入<QFileInfo>
头文件。
让我们在刚才读写文件的例子中,获取一下文件的信息:
#include "Widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
#include <QDateTime>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
b1->setText("读取文本");
b2->setText("写入文本");
layout->addWidget(b1,0,0,1,1);
layout->addWidget(b2,0,1,1,1);
layout->addWidget(editor,1,0,1,2);
this->setLayout(layout);
this->resize(300,400);
connect(b1,&QPushButton::clicked,this,&Widget::openFile);
connect(b2,&QPushButton::clicked,this,&Widget::saveFile);
}
Widget::~Widget()
{
}
void Widget::openFile(){
//生成一个文件对话框并获取文件路径
QString path=QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop","text(*.txt)");
if(!path.isEmpty()){ //若文件路径不为空
//创建QFile对象并指定路径
QFile file(path);
//一定要记得打开文件,并设置读写模式
file.open(QIODevice::ReadOnly);
//读取文件内容,一次性全部读入并保存在字节数组对象array中,默认只识别UTF-8编码的文件,其余编码格式会产生乱码
QByteArray array=file.readAll();
//将读取到的文本内容显示在文本编辑框中
this->editor->setText(array);
//获取文件信息
QFileInfo info(path);
qDebug()<<"文件名:"<<info.fileName();
qDebug()<<"文件大小:"<<info.size();
qDebug()<<"文件类型:"<<info.suffix();
qDebug()<<"文件创建时间:"<<info.created().toString("yyyy-MM-dd hh:mm:ss");
//记得关闭文件
file.close();
}
}
复制代码
实现效果:
说明:文件大小以字节(Byte)为单位。
created()
方法返回一个QDateTime对象,要想以文本形式输出时间,还需要调用toString()
方法,并且指定输出的格式。调用toString()方法需要先引入<QDateTime>
头文件,下面是帮助文档中对于格式的详细描述:
QDataStream读写文件
如果我们想以二进制流的形式对文件进行读写操作,就需要用到QDataStream。使用QDataStream,不仅可以操作文本文件,还可以操作音频、视频等类型的文件。
//Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#pragma execution_character_set("utf-8")
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void Widget::writeStream();
void Widget::readStream();
};
#endif // WIDGET_H
复制代码
#include "Widget.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
//#define cout qDebug()<<"["<<__FILE__<<":"<<__LINE__<<"]"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
writeStream();
readStream();
}
Widget::~Widget()
{
}
void Widget::writeStream(){
//创建一个文档
QFile file("C:/Users/MSI-NB/Desktop/datastream.txt");
//打开文件
file.open(QIODevice::WriteOnly);
//创建一个数据流对象,并与文档关联
QDataStream stream(&file);
//往数据流中写数据,因为数据流与文档关联,所以相当于往文档写数据
stream<<QString("黑色柳丁")<<3155530;
//关闭文件
file.close();
}
复制代码
实现效果:
这个文件就算能直接打开也没有什么意义,因为它的内容是二进制流,所以我们打开看到的是一些乱码,需要通过QDataStream把它读出来,并转换成我们想要的格式。
#include "Widget.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
writeStream();
readStream();
}
Widget::~Widget()
{
}
void Widget::writeStream(){
//创建一个文档
QFile file("C:/Users/MSI-NB/Desktop/datastream.txt");
//打开文件
file.open(QIODevice::WriteOnly);
//创建一个数据流对象,并与文档关联
QDataStream stream(&file);
//往数据流中写数据,因为数据流与文档关联,所以相当于往文档写数据
stream<<QString("黑色柳丁")<<3155530;
//关闭文件
file.close();
}
void Widget::readStream(){
//创建一个文档
QFile file("C:/Users/MSI-NB/Desktop/datastream.txt");
//打开文档
file.open(QIODevice::ReadOnly);
//创建一个数据流对象,并与文档关联
QDataStream stream(&file);
//从数据流中读数据,因为数据流与文档关联,所以相当于从文档读数据
//这里需要定义一些变量来接收输出的内容,会根据类型自动匹配
//写入的顺序与读出的顺序是一致的
QString str;
int num;
stream>>str>>num;
//打印变量值检验结果是否正确
qDebug()<<str.toUtf8().data()<<num;
}
复制代码
注意:从QDataStream对象中输出的数据会根据类型自动匹配,且读取和写入的顺序是一样的,先写入的会先被读取。
实现效果:
Tips:
调试的过程中,经常使用到qDebug(),但是还要打一对括号很麻烦,我们可以定义一个宏,用c++中的输出cout来替代。另外,利用c中的__FILE__
和__LINE__
,可以指示当前语句所在的源文件的文件名
和在文件中的位置
(行数)。(__FILE__和__LINE__都是大小写敏感)
#include "Widget.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
#define cout qDebug()<<"["<<__FILE__<<":"<<__LINE__<<"]" //定义一个便于输出和定位的宏
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
writeStream();
readStream();
}
Widget::~Widget()
{
}
void Widget::writeStream(){
//创建一个文档
QFile file("C:/Users/MSI-NB/Desktop/datastream.txt");
//打开文件
file.open(QIODevice::WriteOnly);
//创建一个数据流对象,并与文档关联
QDataStream stream(&file);
//往数据流中写数据,因为数据流与文档关联,所以相当于往文档写数据
stream<<QString("黑色柳丁")<<3155530;
//关闭文件
file.close();
}
void Widget::readStream(){
//创建一个文档
QFile file("C:/Users/MSI-NB/Desktop/datastream.txt");
//打开文档
file.open(QIODevice::ReadOnly);
//创建一个数据流对象,并与文档关联
QDataStream stream(&file);
//从数据流中读数据,因为数据流与文档关联,所以相当于从文档读数据
//这里定义一些变量来接收输出的内容
//写入的顺序与读出的顺序是一致的
QString str;
int num;
stream>>str>>num;
//打印变量值检验结果是否正确
qDebug()<<str.toUtf8().data()<<num;
cout<<str<<num;
}
复制代码
实现效果:
QTextStream操作文件
要想通过文本的方式操作文件,并为其指定读写的编码,就需要用到QTextStream。QTextStream的用法与QDataStream基本一致。主要的区别是QTextStream对象可以调用setCodec()方法来指定编码方式,参数如下:
但是用这个方式读文件会出现我们不想要的结果,因为它将所有内容都当成是字符串,这样一来,原先跟在QString字符串后面的int型数据也被识别成字符串,所以最好还是用readAll()
或者readLine()
来读取文件。
QBuffer
QBuffer用来操作内存文件。它的用法与QFile差不多,也需要先创建内存文件对象,打开内存文件,写入或读取内存文件,最后关闭内存文件。调用write()方法往内存文件中写入的内存其实是写在缓冲区的,要从缓冲区里把数据取出来,需要调用QBuffer对象的buffer()方法。另外,放到缓冲区的内容会根据写入的顺序依次排列,取出时也是取出缓冲区中所有的内容。
#include "Widget.h"
#include <QBuffer>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
writeFile();
}
Widget::~Widget()
{
}
void Widget::writeFile(){
//创建内存文件
QBuffer memFile;
//打开内存文件
memFile.open(QIODevice::WriteOnly);
//向缓冲区写入数据
memFile.write("hello");
memFile.write("hi");
//关闭文件
memFile.close();
//从缓冲区取出数据
qDebug()<<memFile.buffer();
}
复制代码
实现效果:
在创建QBuffer对象时,可以在构造函数的参数列表中传入一个QByteArray对象,为这个QBuffer对象指定一个缓冲区。那么,在对QBuffer对象调用write()进行写入时,就会将数据写入到QByteArray对象中。
#include "Widget.h"
#include <QBuffer>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
writeFile();
}
Widget::~Widget()
{
}
void Widget::writeFile(){
//创建一个字节数组对象,此时为空
QByteArray array;
//创建一个内存文件并指定array为缓冲区
QBuffer memFile(&array);
//打开内存文件
memFile.open(QIODevice::WriteOnly);
//向缓冲区写入数据
memFile.write("i am writing ");
memFile.write("in buffer");
//关闭文件
memFile.close();
//打印array的值
qDebug()<<"array is "<<array;
}
复制代码
实现效果:
P.S:如有错误,欢迎指正~
近期评论