QT之GUI学习笔记---二进制文件读写

原文地址 :http://devbean.blog.51cto.com/448512/293892


一 读写的基本概念

1.文件读写,即I/O。文件读写经常用于在应用程序中。
Qt 通过 QIODevice 提供了IO的抽象,QIODevice具有读写字节块的能力。
2.常用的IO读写的类
这里写图片描述
QProcess、QTcpSocket、QUdpSoctet 和 QSslSocket 是顺序访问设备,它们的数据只能访问一遍.即你只能从第一个字节开始访问,直到最后一个字节。
QFile、QTemporaryFile 和 QBuffer 是随机访问设备,你可以从任何位置访问任意次数,还可以使用 QIODevice::seek() 函数来重新定位文件指针
3.
QFile 对于访问独立的文件是非常方便的,无论是在文件系统中还是在应用程序的资源文件中。
Qt 同样也提供了 QDir 和 QFileInfo 两个类,用于处理文件夹相关事务以及查看文件信息
4.访问方式
Qt 提供了两个更高级别的抽象:
QDataStream 进行二进制方式的访问;
使用 QTextStream 进行文本方式的访问
这些类可以帮助我们控制字节顺序和文本编码
(1)QDataStream 提供了平台独立的访问数据格式的方法,这些数据格式包括标准的 C++ 类型,如 int、double等;多种 Qt 类型,如QByteArray、QFont、QImage、QPixmap、QString 和 QVariant,以及 Qt 的容器类,如 QList 和 QMap

二 写入文本过程

2.1 代码实例

1.二进制格式访问数据方式—-完成功能
实例化一个 QFile 对象,打开文件;
然后使用 QDataStream 进行访问。
(1)代码

#include "mainwindow.h"
#include <QApplication>
#include<QImage>
#include<QFile>
#include<QMap>
#include<QDataStream>
#include<QString>
#include<QColor>
#include<QIODevice>
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QImage image(":/p.png");

    QMap<QString, QColor> map;
    map.insert("red", Qt::red);
    map.insert("green", Qt::green);
    map.insert("blue", Qt::blue);

    QFile file("facts.dat");
    if (!file.open(QIODevice::WriteOnly)) {
       std::cerr << "Cannot open file for writing: "
                  << qPrintable(file.errorString()) << std::endl;
    }

    QDataStream out(&file);
    out.setVersion(QDataStream::Qt_4_3);

    out << quint32(0x12345678) << image << map;

    return a.exec();
}

(2)运行结果
这里写图片描述
出现乱码的facts.dat
这里写图片描述

2.2 知识点详解

1.
(1)

  QImage image("./p.png");

创建了一个 QImage 对象
(2)

QMap<QString, QColor> map;

创建一个 QMap

QFile file("facts.dat");

使用 QFile 创建了一个名为 “facts.dat” 的文件
(4)

file.open(QIODevice::WriteOnly)

以只写方式打开file文件
(5)

   if (!file.open(QIODevice::WriteOnly)) {
       std::cerr << "Cannot open file for writing: "
                  << qPrintable(file.errorString()) << std::endl;
      return;
    }

如果打开失败,直接 return.同时,输出详细的错误信息
(6)

QDataStream out(&file);  
out.setVersion(QDataStream::Qt_4_3);  

out << quint32(0x12345678) << image << map; 

如果打开成功,我们使用 QFile 的指针创建一个 QDataStream 对象,然后设置 version,这个我们以后再详细说明,最后就像 std 的 cout 一样,使用 << 运算符输出结果。
(7)

0x12345678

0x12345678 成为“魔术数字”,这是二进制文件输出中经常使用的一种技术。我们定义的二进制格式通常具有一个这样的“魔术数字”,用于标志文件格式。
例如,我们在文件最开始写入 0x12345678,在读取的时候首先检查这个数字是不是 0x12345678,如果不是的话,这就不是可识别格式,因此根本不需要去读取。一般二进制格式都会有这么一个魔术数字,例如 Java 的 class 文件的魔术数字就是 0xCAFE BABE(很 Java 的名字),使用二进制查看器就可以查看。魔术数字是一个 32 位的无符号整数,因此我们使用 quint32 宏来得到一个平台无关的 32 位无符号整数。
(8)

qPrintable(file.errorString())

qPrintable() 宏是把 QString 对象转换成 const char *。注意到我们使用的是 C++ 标准错误输出 cerr,因此必须使用这个转换。当然,QString::toStdString() 函数也能够完成同样的操作。




三 读取过程

一.基本要求

读出二进制数据
注意的过程的是读取必须同写入的过程一一对应,即第一个写入 quint32 型的魔术数字,那么第一个读出的也必须是一个 quint32 格式的数据

二 代码

quint32 n;  
QImage image;  
QMap<QString, QColor> map;  

QFile file("facts.dat");  
if (!file.open(QIODevice::ReadOnly)) {  
    std::cerr << "Cannot open file for reading: " 
              << qPrintable(file.errorString()) << std::endl;  
    return;  
}  

QDataStream in(&file);  
in.setVersion(QDataStream::Qt_4_3);  

in >> n >> image >> map; 
in.setVersion(QDataStream::Qt_4_3);  

version的作用:
对于二进制的读写,随着 Qt 的版本升级,可能相同的内容有了不同的读写方式,比如可能由大端写入变成了小端写入等,这样的话旧版本 Qt 写入的内容就不能正确的读出,因此需要设定一个版本号。比如这里我们使用 QDataStream::Qt_4_3,意思是,我们使用 Qt 4.3 的方式写入数据。实际上,现在的最高版本号已经是 QDataStream::Qt_4_6。如果这么写,就是说,4.3 版本之前的 Qt 是不能保证正确读写文件内容的。那么,问题就来了:我们以硬编码的方式写入这个 version,岂不是不能使用最新版的 Qt 的读写了?
解决方法之一是,我们不仅仅写入一个魔术数字,同时写入这个文件的版本。例如:

QFile file("file.xxx");  
file.open(QIODevice::WriteOnly);  
QDataStream out(&file);  

// Write a header with a "magic number" and a version  
out << (quint32)0xA0B0C0D0;  
out << (qint32)123;  

out.setVersion(QDataStream::Qt_4_0);  

// Write the data  
out << lots_of_interesting_data; 

这个 file.xxx 文件的版本号是 123。我们认为,如果版本号是123的话,则可以使用 Qt_4_0 版本读取。所以我们的读取代码就需要判断一下:

QFile file("file.xxx");  
 file.open(QIODevice::ReadOnly);  
 QDataStream in(&file);  

 // Read and check the header  
 quint32 magic;  
 in >> magic;  
 if (magic != 0xA0B0C0D0)  
     return XXX_BAD_FILE_FORMAT;  

 // Read the version  
 qint32 version;  
 in >> version;  
 if (version < 100)  
     return XXX_BAD_FILE_TOO_OLD;  
 if (version > 123)  
     return XXX_BAD_FILE_TOO_NEW;  

 if (version <= 110)  
     in.setVersion(QDataStream::Qt_3_2);  
 else 
     in.setVersion(QDataStream::Qt_4_0);  

 // Read the data  
 in >> lots_of_interesting_data;  
 if (version >= 120)  
     in >> data_new_in_XXX_version_1_2;  
 in >> other_interesting_data; 

这样,我们就可以比较完美的处理二进制格式的数据读写了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值