文件系统:
文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库,提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象,这些设备具有读写字节块的能力。下面是 I/O 设备的类图(Qt5):
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是随机访问设备,
基本文件操作:
文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库,提供了跨平台的文件操作能力。在所有的 I/O 设备中,文件 I/O 是最重要的部分之一。因为我们大多数的程序依旧需要首先访问本地文件(当然,在云计算大行其道的将来,这一观点可能改变)。QFile提供了从文件中读取和写入数据的能力。
我们通常会将文件路径作为参数传给QFile的构造函数。不过也可以在创建好对象最后,使用setFileName()来修改
QFile主要提供了有关文件的各种操作,比如打开文件、关闭文件、刷新文件等。我们可以使用QDataStream
或QTextStream
类来读写文件,也可以使用QIODevice
类提供的read()、readLine()、readAll()
以及write()
这样的函数。值得注意的是,有关文件本身的信息,比如文件名、文件所在目录的名字等,则是通过QFileInfo
获取,而不是自己分析文件路径字符串。
**举个例子:**设计一个文本框,读写数据,保存在本地文件下
写文件:
void Widget::on_btn_write_clicked()
{
QString path = QFileDialog::getSaveFileName(this,"write","../");
if(path.isEmpty() == false)
{
QFile file; //创建对象
file.setFileName(path);
//打开文件,只写
bool isok = file.open(QIODevice::WriteOnly);
if(isok == true)
{
//获取编辑区的内容
QString str = ui->textEdit->toPlainText();
//把读取到的文本写进文件file对象中
//由于文件写函数是qbytearray类型的数据,所以需要在写之前将str转换成bytearray类型
//在qt中有直接转换的函数,toutf8();
file.write(str.toUtf8());
}
file.close();
}
}
1:第一步是设置文件路径QFileDialog
提供了一个对话框,允许用户选择文件或者目录,也允许用户遍历文件系统,用以选择一个或多个文件或者目录。
2:设置文本的名字或者路径
3:打开文本 ,file.open()和file.close()一起用。实际上qt中 文本在关闭时数据才会真正写如进去。你可以不写关闭函数 然后看看文件是否写进去的数据。我们在打开文本的时候,是可以选择打开的格式的,
枚举值 描述
QIODevice::NotOpen 未打开
QIODevice::ReadOnly 以只读方式打开
QIODevice::WriteOnly 以只写方式打开
QIODevice::ReadWrite 以读写方式打开
QIODevice::Append 以追加的方式打开,新增加的内容将被追加到文件末尾
QIODevice::Truncate 以重写的方式打开,在写入新的数据时会将原有 数据全部清除, 游标设置在文件开头。
QIODevice::Text 在读取时,将行结束符转换成 \n;在写入时,将行结束符转换成本地格 式,例如 Win32 平台上是 \r\n
QIODevice::Unbuffered 忽略缓存
读文件:
void Widget::on_btn_read_clicked()
{
QString path = QFileDialog::getOpenFileName(this,"打开","../");
if(path.isEmpty() == false)
{
//创建文件对象
QFile file(path);
bool isok = file.open(QIODevice::ReadOnly); //只读模式打开
if(isok == true)
{
#if 1
//读文件
QByteArray array = file.readAll();
//将数据写进文本框中
ui->textEdit->setText(QString(array));
#else
//一行一行的读
QByteArray array;
while(file.atEnd() == false)
{
array += file.readLine();
}
ui->textEdit->setText(QString(array).toUtf8().data());
#endif
}
file.close();
//获取文件信息
QFileInfo info(path);
qDebug()<<"文件名字:"<< info.fileName();
qDebug()<<"文件后缀:"<< info.suffix();
qDebug()<<"文件大小:"<< info.size();
qDebug()<<"文件创建时间:"<< info.created().toString("yyyy-MM-dd hh:mm:ss"); //yyyy代表年 MMd
}
}
读文件跟写文件差不多,这里我们主要说一下,如果我们需要文件的相关信息,比如路径,大小,格式等。并不是去索引这个文件路径然后获取相关信息。在qt中有一个QFileInfo
的类,他有很多的函数 是用来获取文本信息的。例如:
isDir()检查该文件是否是目录;
isExecutable() 检查该文件是否是可执行文件等。
baseName() 可以直接获得文件名;
completeBaseName() 获取完整的文件名
suffix() 则直接获取文件后缀名。
completeSuffix() 获取完整的文件后缀
//获取文件信息
QFileInfo info(path);
qDebug()<<"文件名字:"<< info.fileName();
qDebug()<<"文件后缀:"<< info.suffix();
qDebug()<<"文件大小:"<< info.size();
qDebug()<<"文件创建时间:"<< info.created().toString("yyyy-MM-dd hh:mm:ss");
以上我们读写文件方式都是使用的QIODevice
提供的函数,接下来我们看看怎么使用QDataStream二进制读写文件。
QDataStream提供了基于QIODevice的二进制数据的序列化。数据流是一种二进制流,这种流完全不依赖于底层操作系统、CPU 或者字节顺序(大端或小端)。例如,在安装了 Windows 平台的 PC 上面写入的一个数据流,可以不经过任何处理,直接拿到运行了 Solaris 的 SPARC 机器上读取。由于数据流就是二进制流,因此我们也可以直接读写没有编码的二进制数据,例如图像、视频、音频等。
QDataStream既能够存取 C++ 基本类型,如 int、char、short 等,也可以存取复杂的数据类型,例如自定义的类。实际上,QDataStream对于类的存储,是将复杂的类分割为很多基本单元实现的。
二进制文件写操作:
//创建文件 对象
QFile file("../test.txt");
bool isok = file.open(QIODevice::WriteOnly);
if(isok == true)
{
//创建数据流,和file文件关联起来,向数据流里面输入数据时,就是往文件里面写数据
QDataStream stream(&file); //stream 是二进制的数据,在文本显示为乱码
stream << QString("主要看气质") << 250;
file.close();
}
二进制文件读操作:把写进去的数据读出来
//创建文件 对象
QFile file("../test.txt");
bool isok = file.open(QIODevice::ReadOnly);
if(isok == true)
{
QDataStream stream(&file);
//读取数据时 按照写入的顺序读取
QString str;
int a;
stream >> str >>a ;
cout << str.toUtf8().data() << a;
}
唯一需要注意的是,你必须按照写入的顺序,将数据读取出来。顺序颠倒的话,程序行为是不确定的,严重时会直接造成程序崩溃 就是我先写的qstring的值,然后再写的int值。我们在读取的时候也是先取出qstring的值 然后在读取int型的值。循序不能出错
那么,既然QIODevice提供了read()、readLine()之类的函数,为什么还要有QDataStream呢?QDataStream同QIODevice有什么区别?区别在于,QDataStream提供流的形式,性能上一般比直接调用原始 API 更好一些。
文本文件读写
虽然QTextStream的写入内容与QDataStream一致,区别在于读取时不一致:
在 QDataStream
中读取数据时,stream >> str >>a ; cout << str.toUtf8().data() << a;
在QTextStream
中读取数据时,stream >>str ; cout << str;
两者的输出结果都是一样的,可以看出在使用QTextStream
的时候,不需要定义一个int的变量a来存储读出的int类型的数据250。这是因为当使用QDataStream写入的时候,实际上会在要写入的内容前面,额外添加一个这段内容的长度值。而以文本形式写入数据,是没有数据之间的分隔的。