文件操作概述
1、Qt中IO操作的处理方式
(1)、Qt通过统一的接口简化了文件与外部设备的操作方式
(2)、Qt中的文件被看做是一种特殊的外部设备
(3)、Qt中的文件操作与外部设备操作相同
2、IO操作中的关键函数接口
注意:IO操作的本质:连续存储空间的数据读写
3、Qt中IO设备类型
(1)、顺序存储设备:只能从头开始顺序读写数据,不能指定数据的读写位置(串口)
(2)、随机存储设备:可以定位到任意位置进行数据读写(seek function函数)(文件)
4、Qt中IO设备 的继承层次图
5、QT文件操作类型
QFile | QFile是Qt中用于文件操作的类 QFile直接支持文本文件:文件内容是可读的文本字符、 和数据文件:文件内容是直接的二进制数据的读写 |
QFineInfo | 用于读取文件属性信息 |
QTemPoraryFile | 安全创建全局唯一的临时文件、临时文件用于大数据传递或者进程间通信的场合 |
QTextStream | 写入的数据全部转化为可读文本 |
QDataStream | 写入的数据根据类型转换为二进制 |
QBuffer | 缓冲区的本质为一段连续的存储空间、QBuffer是qt中缓冲区相关的类 |
QDir | 是Qt中功能强大的目录操作类 |
QFileSystemWatcher | 用于监控文件和目录的状态变化(内容、重命名、删除) |
QFile操作
mainwindow.cpp:
#include "mainwindow.h"
#include <QApplication>
#define chineseToQString(pChineseText) QTextCodec::codecForName("GB2312")->toUnicode(pChineseText)
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->setWindowTitle("qfile test");
QWidget* w=new QWidget;
setCentralWidget(w);
buttonRead->setText("buttonRead");
buttonWrite->setText("buttonWrite");
QHBoxLayout* hlayout=new QHBoxLayout;
hlayout->addStretch(1);
hlayout->addWidget(buttonRead);
hlayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding));
hlayout->addWidget(buttonWrite);
hlayout->addStretch(1);
QVBoxLayout*container = new QVBoxLayout();
container->addLayout(hlayout);
container->addWidget(textEdit);
centralWidget()->setLayout(container);
this->resize(600, 400);
connect(buttonRead,&QPushButton::clicked,this,&MainWindow::on_readData);
connect(buttonWrite,&QPushButton::clicked,this,&MainWindow::on_writeData);
}
void MainWindow::on_readData()
{
QString path = QFileDialog::getOpenFileName(this,"open", "../", "TXT(*.txt)");
if(path.isEmpty() == false){
QFile file(path); //文件对象
bool isOk = file.open(QIODevice::ReadOnly);//打开文件,只读方式
if(isOk == true) {
#if 0
QByteArray array = file.readAll();//读文件,默认只识别utf8编码
textEdit->setText(QString(array)); //显示到编辑区
textEdit->setText(array);
#endif
QByteArray array;
while( file.atEnd() == false) {
//读一行
array += file.readLine();
}
textEdit->setText(array);
}
file.close();//关闭文件
//获取文件信息
QFileInfo info(path);
qDebug() << "文件路径:"<< info.path();
qDebug() << "文件名字:" << info.fileName().toUtf8().data();
qDebug() << "文件后缀:" << info.suffix();
qDebug() << "文件大小:" << info.size();
qDebug() << "文件创建时间:" <<
info.created().toString("yyyy-MM-dd hh:mm:ss");
qDebug() << info.exists();
qDebug() << info.isFile();
qDebug() << info.isReadable();
qDebug() << info.isWritable();
qDebug() << info.lastRead();
qDebug() << info.lastModified();//最后修改时间
qDebug() << info.isExecutable(); // 是否是可执行文件
qDebug() << info.isDir(); // 是否是目录
qDebug() << info.isFile(); // 是否是文件
}
}
void MainWindow::on_writeData()
{
QString path = QFileDialog::getSaveFileName(this, "save", "../", "TXT(*.txt)");
if(path.isEmpty() == false) {
QFile file; //创建文件对象
file.setFileName(path);//关联文件名字
bool isOk = file.open(QIODevice::WriteOnly);//打开文件,只写方式
if(isOk == true) {
QString str = textEdit->toPlainText();//获取编辑区内容
file.write(str.toUtf8()); //QString -> QByteArray
file.write(str.toStdString().data());//QString -> c++ string -> char *
//file.write(str.toLocal8Bit());//转换为本地平台编码
}
file.close();
}
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QRadioButton>
#include <QStringList>
#include <QLineEdit>
#include <QGridLayout>
#include <QFormLayout>
#include <QTextCodec>
#include <QListWidget>
#include <QLabel>
#include <QStackedLayout>
#include <QTextEdit>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QDebug>
#include <QDateTime>
#include <QDataStream>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_readData();
void on_writeData();
private:
QPushButton *buttonRead = new QPushButton();
QPushButton *buttonWrite = new QPushButton();
QTextEdit *textEdit = new QTextEdit();
};
#endif // MAINWINDOW_H
运行结果:
qfile读写16进制数据
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QIODevice>
#define HexPrint(packet, len)\
do{\
QByteArray data((const char*)packet, len); \
QString hexString; \
for (int i = 0; i < data.size(); i++) { \
hexString += QString("%1 ").arg((quint8)data.at(i), 2, 16, QChar('0')); \
} \
qDebug() << hexString; \
}while(0);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
writeDataToFile();
readDataFromFile();
}
void MainWindow::writeDataToFile(void)
{
QFile file("qfile_test.dat");
if (!file.open(QIODevice::WriteOnly)) {
// Handle error
return;
}
uint8_t data_buf[32] ={
0x55,0xAA,0xD9,0x6E,0x1A,0x00,0x04,0x00,0x1A,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x66,0xBB,0xD9,0x6E,0x1A,0x00,0x04,0x00,0x1A,0x00,0x01,0x00,0x00,0x00,0x00,0x00
};
QByteArray b_data((const char *)&data_buf,sizeof(data_buf));
qint64 i64WriteBytes = file.write(b_data);
if( b_data.length() != i64WriteBytes ){
qDebug()<<"write data len err";
}
file.close();
}
void MainWindow::readDataFromFile(void)
{
QFile file("qfile_test.dat");
if (!file.open(QIODevice::ReadOnly)) {
// Handle error
return;
}
QByteArray qbaData;
file.seek(0);
qbaData = file.readAll();
if( qbaData.length() != file.size() ){
qDebug()<<"read data len err";
}
qDebug()<<"read data:";
HexPrint(qbaData.data(),qbaData.size());
}
QDataStream操作
读写16进制数据
读写quint16、和quint32类型的数据:
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QIODevice>
#include <QString>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
writeDataToFile();
readDataFromFile();
}
void MainWindow::writeDataToFile(void)
{
QFile file("test.dat");
if (!file.open(QIODevice::WriteOnly)) {
// Handle error
return;
}
QDataStream out(&file);
out.setByteOrder(QDataStream::LittleEndian); // 设置字节序为小端
out << (quint16)0x1234;// 写入16进制数据
out << (quint32)0xABCDEF12;
QString qstr = "testString";
out << qstr;
file.close();
}
void MainWindow::readDataFromFile(void)
{
QFile file("test.dat");
if (!file.open(QIODevice::ReadOnly)) {
// Handle error
return;
}
QDataStream in(&file);
in.setByteOrder(QDataStream::LittleEndian); // 设置字节序为小端
quint16 value16;
quint32 value32;
QString qstr = "";
//读的时候,按写的顺序取数据
in >> value16; // 读取一个16位无符号整数
in >> value32; // 读取一个32位无符号整数
in >> qstr;
file.close();
qDebug("src:0x1234,read data: 0x%X\n",value16);// 使用读取的数据
qDebug("src:0xABCDEF12,read data: 0x%X",value32);
qDebug()<<"read qstr:"<<qstr;
}
写到文件的数据:
从文件读取数据放置对应的类型的变量,变量打印如下:
读写uint8_t类型的数据buffer:
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QIODevice>
#define HexPrint(packet, len)\
do{\
QByteArray data((const char*)packet, len); \
QString hexString; \
for (int i = 0; i < data.size(); i++) { \
hexString += QString("%1 ").arg((quint8)data.at(i), 2, 16, QChar('0')); \
} \
qDebug() << hexString; \
}while(0);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
writeDataToFile();
readDataFromFile();
}
void MainWindow::writeDataToFile(void)
{
QFile file("test.dat");
if (!file.open(QIODevice::WriteOnly)) {
// Handle error
return;
}
QDataStream out(&file);//等价 QDataStream out;out.setDevice(&file);
uint8_t data_buf[32] ={
0x55,0xAA,0xD9,0x6E,0x1A,0x00,0x04,0x00,0x1A,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x66,0xBB,0xD9,0x6E,0x1A,0x00,0x04,0x00,0x1A,0x00,0x01,0x00,0x00,0x00,0x00,0x00
};
for(int i=0;i<sizeof(data_buf);i++){
out << data_buf[i];
}
file.close();
}
void MainWindow::readDataFromFile(void)
{
QFile file("test.dat");
if (!file.open(QIODevice::ReadOnly)) {
// Handle error
return;
}
QDataStream in(&file);
char data_buf[32];
for(int i=0;i<sizeof(data_buf)/8;i++){
in.readRawData(data_buf, 8);
HexPrint(data_buf,8);
}
}
QTextStream
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QIODevice>
#include <QString>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
writeDataToFile();
readDataFromFile();
}
void MainWindow::writeDataToFile(void)
{
QFile file("test.txt");
if (!file.open(QIODevice::WriteOnly)) {
// Handle error
return;
}
QTextStream stream(&file);
stream.setCodec("UTF-8");//指定编码
stream << QString("QTextStream test") << 200;
file.close();
}
void MainWindow::readDataFromFile(void)
{
QFile file;
file.setFileName("test.txt");
if (!file.open(QIODevice::ReadOnly)) {
// Handle error
return;
}
QTextStream stream(&file);
stream.setCodec("UTF-8");//指定编码
#if 0
QString str;
int a;
stream >> str >> a;
qDebug() << str.toUtf8().data()<< a;
#endif
QString str = stream.readAll();
qDebug() << str.toUtf8().data();
file.close();
}
运行打印结果:
QTextStream test200
QBuffer操作
与文件一样都是IO操作,方式也类似
1、文件需要QFile与一个实际文件相关联,缓冲区需要QBuffer与一片存储空间(QByteArray定义的)相关联
2、文件的打开需要QFile的对象来打开,缓冲区的打开需要QBuffer的对象来打开
3、写入和读出数据一般都需要QFile(或QBuffer)对象与QDataStream(或QTextStream)相关联
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QIODevice>
#include <QString>
#include <QTextStream>
#include <QBuffer>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
writeDataToFile();
//readDataFromFile();
}
void MainWindow::writeDataToFile(void)
{
QByteArray ba;
QBuffer buffer(&ba);
if(buffer.open(QIODevice::WriteOnly))//以只写二进制的形式打开
{
QDataStream out(&buffer);
out << QString("QBuffer_Test");
out << 520;
out << 13.14;
buffer.close();
}
if(buffer.open(QIODevice::ReadOnly))//读数据,也是使用上面定义的buf
{
QDataStream in(&buffer);
QString str;
int i_value;
double d_value;
in >> str;
in >> i_value;
in >> d_value;
qDebug()<<"Qstring = " << str;
qDebug()<<"int value = " <<i_value;
qDebug()<<"double value = " <<d_value;
buffer.close();
}
}
运行打印结果:
Qstring = "QBuffer_Test"
int value = 520
double value = 13.14
注意:如果重新定义一个函数读数据, 读写定义的Qbuffer不同了;那读出来的数据肯定不同;
QByteArray ba; QBuffer buffer(&ba);
void MainWindow::readDataFromFile(void)
{
/*
QByteArray ba;
QBuffer buffer(&ba);//要跟写数据的同一个变量,可以定义全局变量
if(buffer.open(QIODevice::ReadOnly))
{
QDataStream in(&buffer);
QString str;
int i_value;
double d_value;
in >> str;
//in >> i_value;
//in >> d_value;
qDebug()<<"Qstring = " << str;
// qDebug()<<"int value = " <<i_value;
// qDebug()<<"double value = " <<d_value;
buffer.close();
}
*/
}
QDir操作
QDir类在很多实际应用场景中都能发挥作用,比如:
1.文件和目录管理:在应用程序中进行文件和目录的创建、复制、删除和重命名等操作,实现数据的管理和存储。
2.批量处理:当可以使用QDir类遍历目录中的所有文件,然后对每个文件进行相应操作。
3.目录比较:比较两个目录中的文件和子目录,查找差异或进行同步操作。
4.文件搜索:使用QDir类的entryList()函数配合正则表达式,可以实现对目录中符合特定规则的文件进行搜索。
5.日志管理:在记录日志的时候,可以使用QDir类创建和管理日志文件。
获取当前目录和目录创建
QString currentPath = QDir::currentPath();// 获取当前目录
qDebug()<<"currentPath :"<< currentPath;
QDir dir;
if (!dir.exists("new_dir")) {//如果没有这个文件夹
bool ok = dir.mkpath("new_dir");//创建文件夹
}
//或者
QDir dir1;
if (dir1.mkdir("new_dir1")) {
// 目录创建成功
} else {
// 目录已存在或创建失败
}
扫描文件夹指定后缀的文件,如下需要列出.isp结尾的文件:
void MainWindow::dir_test(QString path)
{
QStringList filePathList;
filePathList.clear();
QString dirPath = "dir_test";
QDirIterator it(dirPath, QStringList() << "*.isp", QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while(it.hasNext()){
it.next();
filePathList.append(it.fileInfo().absoluteFilePath());
}
qDebug()<<"fileList.size() ="<< filePathList.size();
qDebug()<< filePathList;
for(int i = 0; i< filePathList.size();++i){
QString fileName = filePathList.at(i);
qDebug()<<".isp file path :"<< fileName;
}
}
子文件夹的文件也被递归列出来了
列出目录和筛选目录内容
QDir dir("dir_test");
//仅获取目录下的文件列表,而不包含子目录,而忽略子目录的内容。
// QStringList filesAndDirs = dir.entryList(QDir::Files);//使用QDir::Files过滤器
QStringList filesAndDirs = dir.entryList();
foreach (const QString& name, filesAndDirs) {
qDebug()<<"file name: "<< name;
}
过滤文件夹内容对比
QDir::Dirs:获取目录下的所有子目录。
QDir::AllEntries:获取目录下的所有文件和子目录(包括隐藏文件和隐藏目录)。
QDir::NoDotAndDotDot:排除特殊目录.和..。
QDir::Hidden:获取隐藏的文件和目录。
使用entryList()函数的重载版本,指定一个文件过滤器来选择只包含.ini扩展名的文件。以下是只打印出目录中的.ini文件:
QDir directory("/path/to/your/directory"); // 修改为你想遍历的目录路径
QStringList iniFiles = directory.entryList(QStringList() << "*.ini", QDir::Files);
foreach (const QString& iniFile, iniFiles) {
qDebug() << "INI File:" << iniFile;
}
复制文件和目录
QFile::copy("sourceFile.txt", "destinationFile.txt");
QDir directory;
directory.rename("sourceDirectory", "destinationDirectory");
删除文件和目录
QFile::remove("fileToRemove.txt");
QDir directory;
directory.rmdir("directoryToRemove");
更改文件名
bool renameFile(const QString& directoryPath, const QString& oldFileName, const QString& newFileName)
{
QDir directory(directoryPath);
if (directory.exists(oldFileName)) {
if (directory.rename(oldFileName, newFileName)) {
qDebug() << "File renaming successful!";
return true;
} else {
qDebug() << "File renaming failed!";
return false;
}
} else {
qDebug() << "File not found!";
return false;
}
}