qt - 文件

qt-文件操作

文件读写、创建、删除、重命名、拷贝
可操作:文本文件二进制文件

文件对话框

#include <QFileDialog>
#include <QString>
#include <QDebug>

/*
    静态数据成员:
        类的一部分,为类的所有实例共享,处在静态区
        类名::静态成员访问
    非静态数据成员:
        实例的一部分,类的每个实例都有一份拷贝,处在动态区

        静态函数成员与非静态函数成员,都为类所有,实例对象不存在函数的拷贝
        静态函数成员:
        类名::方法 或者 实例对象.方法
        编译器不向函数传递this指针,不识别实例对象个体,经常用来操作静态数据成员(要访问类的非静态成员可以通过对象来实现)
        非静态函数成员:
        实例对象.方法 或者 实例对象->方法
        调用时编译器向函数传递this指针
*/

// 使用静态成员函数的方法调用
QString filename=QFileDialog::getOpenFileName(this,
                                                "open file",
                                                "f:\\",
                                                tr("images(*.png *.jpg)")); // tr是字体兼容性的问题
qDebug()<<filename;

字体对话框

#include <QFontDialog>
#include <QString>
#include <QDebug>

bool ok; // 标志是否选择一个字体
QFont font=QFontDialog::getFont(&ok,this); // 返回一个字体

if (ok)
{
    ui->FontButton->setFont(font);
}
else
{
    qDebug()<<"not font be choiced!";
}

输入对话框 – 字符串\数字

void MainWindow::on_InputButton_clicked()
{
    bool flag; // 是否有输入
    // QLineEdit:: 显示的模式 // 关键参数是LineEdit::Normal lineEidt::password
    // password 默认提示字符
    QString input=QInputDialog::getText(this,"输入对话框","请输入用户名",QLineEdit::Normal,"password",&flag);
    if (flag)
    {
        qDebug()<<input;
    }

    bool flag_val;
    int val=QInputDialog::getInt(this,"输入对话框","0-100",0,0,256,1,&flag_val);
    if (flag)
    {
        qDebug()<<val;
    }
}

QMessageBox 消息对话框

// 问题对话框
int ret=QMessageBox::question(this,
                        "question", // 对话框的标题
                        "ues Qt T or F", // 对话框的内容
                        QMessageBox::Yes, // 可选择的模式
                        QMessageBox::No);
if (ret==QMessageBox::yes)
{
    qDebug()<<"yes";
}

// 提示对话框
QMessageBox::information(this,
                            "notice",
                            "best to ues qt",
                            QMessageBox::Ok);


//警告对话框
QMessageBox::warning(this,
                        "warning",
                        "warning...",
                        QMessageBox::Ok);

// 关于对话框...

进度对话框

#include <QProgressBox>

// 静态成员函数 可以利用 类名::静态成员函数
// 非静态成员函数 可以利用 类名 对象的方式创建
/*
    静态数据成员:
        类的一部分,为类的所有实例共享,处在静态区
        类名::静态成员访问
    非静态数据成员:
        实例的一部分,类的每个实例都有一份拷贝,处在动态区

        静态函数成员与非静态函数成员,都为类所有,实例对象不存在函数的拷贝
        静态函数成员:
        类名::方法 或者 实例对象.方法
        编译器不向函数传递this指针,不识别实例对象个体,经常用来操作静态数据成员(要访问类的非静态成员可以通过对象来实现)
        非静态函数成员:
        实例对象.方法 或者 实例对象->方法
        调用时编译器向函数传递this指针
*/

// 该类没有静态成员函数,所以只能通过创建对象来实现

// 堆中 全局,不释放
// 由于没有delete 加上对象树的概念,会一直消耗内存
//    QProgressDialog *prodlg=new QProgressDialog(this);

// 栈中 局部,释放
QProgressDialog prodlg("copy progress",
                        "stop",
                        0,
                        50000,
                        this);

// 设置模态
prodlg.setWindowModality(Qt::WindowModal);
prodlg.setWindowTitle("copy file");
prodlg.show();

for (int i=0;i<50000;i++)
{
    prodlg.setValue(i);
    // 类似并发 多线程 强制每隔一段时间还有没有其他时间没做完
    // copy的同时 检测还有没有其他的事情要做
    QCoreApplication::processEvents();

    if (prodlg.wasCanceled()) // 当点击取消的时候
    {
        qDebug()<<"stop copy...";
//            break;
        return ;
    }
    prodlg.setValue(50000);

}
qDebug()<<"copy done...";

文本文件

#include <QApplication>
#include <QDebug>
#include <QFile>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 创建QFile对象,同时指定要操作的文件
    // 注意这个文件(在使用相对路径的时候)会与可执行文件exe处于同一个路径文件夹下
    QFile file("./demo.txt");

    if (!file.open(QIODevice::WriteOnly|QIODevice::Text)){
        qDebug()<<"文件打开失败"; // 相当于cout,qDebug还有更高级的用法
    }

    // 向文件中写入字符串
    file.write("ex\n");
    file.write("ex2\n");
    //关闭文件
    file.close();

    //重新打开文件,对文件进行读操作
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)){
        qDebug()<<"文件打开失败";
    }

    // 每次都读取一行
    // 创建一个字符串(字符串数组)
    char* str=new char[100];
    // 每次从文件中读取一行数据或读取最多maxSize-1个字节,存储到data中
    // 返回读取到的字节数
    qint64 readNum=file.readLine(str,100);

    // 当读取出现错误 (返回为-1)或者读取到字符数为0时,结束读取
    while ((readNum!=0)&&(readNum!=-1)){
        qDebug()<<str;
        readNum=file.readLine(str,100); // 会覆盖
    }

    file.close();
    return 0;
}

二进制文件

int main(int argc, char *argv[])
{
    QApplication a(argc, 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("./demo_byte.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;
}

文件操作实例

#include <QFileDialog>
#include <QFile>
#include <QFileInfo>
#include <QDebug>

/* 文件读写  */
QString fileName=QFileDialog::getOpenFileName(this,"打开文件","./"); // 可以是相对路径

// 显示文件名
ui->lineEdit->setText(fileName);

//打开文件
QFile file(fileName);
file.open(QIODevice::ReadOnly); // 只读方式

// 读取全部内容
QByteArray array=file.readAll(); // read(size)读取指定个字节大小
ui->textEdit->setText(array); // QByteArray -> QString 隐式转换

// 判断是否到文件末尾
ui->textEdit->clear();
file.seek(0);
while (!file.atEnd())
{
    QByteArray lineArray=file.readLine();
    ui->textEdit->append(lineArray);
}

file.close();

file.open(QIODevice::Append);
file.write("\nhello vs\n"); // 这种才是正确的写法
file.write("hello vs code\n");
file.close();

/* 文件属性 */
QFile file2("./test.txt");
QFileInfo file2_info(file2); // 文件信息
qDebug()<<file2_info.absoluteFilePath(); // 文件绝对路径
qDebug()<<file2_info.fileName();
qDebug()<<file2_info.suffix(); // 后缀名
#if QT_VERSION>0x060000
    qDebug()<<file2_info.birthTime().date();
    qDebug()<<file2_info.birthTime().time();
    qDebug()<<file2_info.birthTime().toString("yyyy.MM.dd hh::mm::ss");
#else
    qDebug()<<file2_info.created();
#endif

/* 文件定位 */
file2.open(QIODevice::ReadOnly);
file2.seek(0); // 文件指针指向开头的位置
QByteArray array2=file2.read(5);
qDebug()<<"first 5 byte "<<array2;
qDebug()<<"current file ptr pos "<<file2.pos();
// file.seek(pos) 读取的是从pos+1个字节开始的(pos==1为第一个字节)
file2.close();

文件监视/过滤

private slots:
    void showDirMessage(const QString &path); // 传递一个路径,引用方式,且不希望被修改

private:
    Ui::Widget *ui;

    QFileSystemWatcher monitor;

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QDir>
#include <QStringList>
#include <QFileSystemWatcher> // 文件监视器

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

    QDir mydir(QDir::currentPath());
    qDebug()<<mydir;

    QDir mydir2("f:/qt-learning/exp10");
    ui->listWidget->addItem(mydir2.absolutePath());
    ui->listWidget->addItems(mydir2.entryList());

    // 设置文件类型过滤器
    mydir2.setNameFilters(QStringList("*.cpp"));

    // 文件监视器 判断是否有改动:删除、改动、增加
    mydir2.mkdir("monitorDir");

    connect(&monitor,&QFileSystemWatcher::directoryChanged,this,&Widget::showDirMessage); // 监视文件夹变化
    connect(&monitor,&QFileSystemWatcher::fileChanged,this,&Widget::showDirMessage); // 监视文件变化
    monitor.addPath("f:/qt-learning/exp10/monitorDir"); // 监视文件夹
    monitor.addPath("f:/qt-learning/exp10/monitorDir/test.txt"); // 监视文件

}

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

void Widget::showDirMessage(const QString &path)
{
    if (path=="f:/qt-learning/exp10/monitorDir")
    {
        ui->listWidget->addItem("f:/qt-learning/exp10/monitorDir 目录发生改变");
    }
    else if (path=="f:/qt-learning/exp10/monitorDir/test.txt")
    {
        ui->listWidget->addItem("f:/qt-learning/exp10/monitorDir/test.txt 文件发生改变");
    }
}


文件操作进阶

QTextStream

/*
    QTextStream 类 提供了很多读写文件相关方法
*/
#include <QFile>
#include <QDebug>
#include <QString>
#include <QTextStream>

int main(int argc,char* argv[]){
    // 创建QFile对象
    QFile file("./demo2.txt");
    // 对文件进行写操作
    if (!file.open(QIODevice::WriteOnly|QIODevice::Text)){
        qDebug()<<"文件打开失败";
    }

    QTextStream out(&file); // 将文件转换为文本流的方式进行存储
    //QTextStream类重载了运算符<< >>
    out<<(QString)"ex1\n"<<(QString)"ex2";
    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;
}

例子2

注意readline \n 的问题没有解决???

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QFile>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTextStream>

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

    QString fileName=QFileDialog::getOpenFileName(this,"打开文件","./");
    ui->lineEdit->setText(fileName);

    QFile file(fileName);
    file.open(QIODevice::ReadOnly);

    // 创建文本流
    // 将一个文件关联一个流,将文件转换为流
    // 操作这个流 等于 操作这个文件
    QTextStream textStream(&file);
    textStream.setEncoding(QStringConverter::Utf8); // 设置流的编码方式

    QByteArray streamArray;
    while (!textStream.atEnd())
    {
        streamArray+=textStream.readLine().toUtf8();
    }
    ui->textEdit->setText(streamArray);

    file.close();
}

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

QDataStream

https://blog.csdn.net/qq_38832450/article/details/102587454

例子1

QFile file2("./test2.dat");
file2.open(QIODevice::WriteOnly);

// 将文件绑定到数据流上
QDataStream dataInStream(&file2);
dataInStream<<QString("hello world")<<QString("hello qt")<<(qint32)65;

file2.close();

file2.open(QIODevice::ReadOnly);
QDataStream dataOutStream(&file2);
QString str1,str2;
qint32 num;
dataOutStream>>str1>>str2>>num;
qDebug()<<str1<<str2<<num;
//    dataOutStream>>str1>>num; // ERROR
//    qDebug()<<str1<<num; // ERROR
file2.close();
  • QDataStream 与QByteArray

https://blog.csdn.net/qq_40206060/article/details/111614662
借助QDataStream 实现数据与QByteArray的关联,输入与输出

伪代码

/* 数据流操作音视频 */
// 伪代码
QImage image("path");
QByteArray imageArray; // 相当于内存区域,内存块
// 通过流的方式,对内存块进行读写操作
QDataStream imageStream(&imageArray,QIODevice::ReadWrite); // 将数据流绑定到内存块
// 通过数据流的方式,将数据保存到内存块中
imageStream<<imag

进阶思考

QStringQDataStream 后会增加一些头数据,比如文本的长度

QFile file("./7.信号和槽.wmv");
QFileInfo info(file.fileName());
qDebug()<<info.fileName()<<" "<<info.size(); // "7.信号和槽.wmv"   125554598
QByteArray arr26=info.fileName().toUtf8();
qDebug()<<arr26<<" "<<arr26.toHex()<<" "<<arr26.size(); // "7.\xE4\xBF\xA1\xE5\x8F\xB7\xE5\x92\x8C\xE6\xA7\xBD.wmv"   "372ee4bfa1e58fb7e5928ce6a7bd2e776d76"   18


QByteArray arr27;
QDataStream out(&arr27,QIODevice::WriteOnly);
out<<info.fileName();
qDebug()<<arr27<<" "<<arr27.toHex()<<" "<<arr27.size(); // "\x00\x00\x00\x14\x00""7\x00.O\xE1S\xF7T\x8Ci\xFD\x00.\x00w\x00m\x00v"   "000000140037002e4fe153f7548c69fd002e0077006d0076"   24

QDataStream in(&arr27,QIODevice::ReadOnly);
QString filename;
in>>filename;
qDebug()<<filename; // "7.信号和槽.wmv"

QByteArray arr28;
QDataStream out2(&arr28,QIODevice::WriteOnly);
out2<<info.fileName().toUtf8();
qDebug()<<info.fileName().toUtf8().size(); // 18
qDebug()<<arr28<<" "<<arr28.toHex()<<" "<<arr28.size(); // "\x00\x00\x00\x12""7.\xE4\xBF\xA1\xE5\x8F\xB7\xE5\x92\x8C\xE6\xA7\xBD.wmv"   "00000012372ee4bfa1e58fb7e5928ce6a7bd2e776d76"   22

QDataStream in2(&arr28,QIODevice::ReadOnly);
QByteArray filename2;
in2>>filename2;
qDebug()<<filename2<<" "<<QString(filename2); // "7.\xE4\xBF\xA1\xE5\x8F\xB7\xE5\x92\x8C\xE6\xA7\xBD.wmv"   "7.信号和槽.wmv"

QBuffer

QBuffer 是操作QByteArray的接口类
QDataStream 是一个操作QBuffer的接口类