今天开始进入 Qt 的另一个部分:文件读写,也就是 IO。文件读写在很多应用程序中都是需要的。Qt 通过 QIODevice 提供了IO的抽象,这种设备(device)具有读写字节块的能力。常用的IO读写的类包括以下几个:
QFlie 访问本地文件系统或者嵌入资源
QTemporaryFile 创建和访问本地文件系统的临时文件
QBuffer 读写 QByteArray
QProcess 运行外部程序,处理进程间通讯
QTcpSocket TCP 协议网络数据传输
QUdpSocket 传输 UDP 报文
QSslSocket 使用 SSL/TLS 传输数据
QProcess、QTcpSocket、QUdpSoctet 和 QSslSocket 是顺序访问设备,它们的数据只能访问一遍,也就是说,你只能从第一个字节开始访问,直到最后一个字节。QFile、QTemporaryFile 和 QBuffer 是随机访问设备,你可以从任何位置访问任意次数,还可以使用 QIODevice::seek() 函数来重新定位文件指针。
在访问方式上,Qt 提供了两个更高级别的抽象:使用 QDataStream 进行二进制方式的访问和使用 QTextStream 进行文本方式的访问。这些类可以帮助我们控制字节顺序和文本编码,使程序员从这种问题中解脱出来。
QFile 对于访问独立的文件是非常方便的,无论是在文件系统中还是在应用程序的资源文件中。Qt 同样也提供了 QDir 和 QFileInfo 两个类,用于处理文件夹相关事务以及查看文件信息等。
这次我们先从二进制文件的读写说起。
以二进制格式访问数据的最简单的方式是实例化一个 QFile 对象,打开文件,然后使用 QDataStream 进行访问。QDataStream 提供了平台独立的访问数据格式的方法,这些数据格式包括标准的 C++ 类型,如 int、double等;多种 Qt 类型,如QByteArray、QFont、QImage、QPixmap、QString 和 QVariant,以及 Qt 的容器类,如 QList<T> 和 QMap<K, T>。先看如下的代码:
  1. QImage p_w_picpath("philip.png");
  2. QMap<QString, QColor> map;
  3. map.insert("red", Qt::red);
  4. map.insert("green", Qt::green);
  5. map.insert("blue", Qt::blue);
  6. QFile file("facts.dat");
  7. if (!file.open(QIODevice::WriteOnly)) {
  8. std::cerr << "Cannot open file for writing: "
  9. << qPrintable(file.errorString()) << std::endl;
  10. return;
  11. }
  12. QDataStream out(&file);
  13. out.setVersion(QDataStream::Qt_4_3);
  14. out << quint32(0x12345678) << p_w_picpath << map;
这里,我们首先创建了一个 QImage 对象,一个 QMap<QString, QColor>,然后使用 QFile 创建了一个名为 "facts.dat" 的文件,然后以只写方式打开。如果打开失败,直接 return;否则我们使用 QFile 的指针创建一个 QDataStream 对象,然后设置 version,这个我们以后再详细说明,最后就像 std 的 cout 一样,使用 << 运算符输出结果。
0x12345678 成为“魔术数字”,这是二进制文件输出中经常使用的一种技术。我们定义的二进制格式通常具有一个这样的“魔术数字”,用于标志文件格式。例如,我们在文件最开始写入 0x12345678,在读取的时候首先检查这个数字是不是 0x12345678,如果不是的话,这就不是可识别格式,因此根本不需要去读取。一般二进制格式都会有这么一个魔术数字,例如 Java 的 class 文件的魔术数字就是 0xCAFE BABE(很 Java 的名字),使用二进制查看器就可以查看。魔术数字是一个 32 位的无符号整数,因此我们使用 quint32 宏来得到一个平台无关的 32 位无符号整数。
在这段代码中我们使用了一个 qPrintable() 宏,这个宏实际上是把 QString 对象转换成 const char *。注意到我们使用的是 C++ 标准错误输出 cerr,因此必须使用这个转换。当然,QString::toStdString() 函数也能够完成同样的操作。
读取的过程就很简单了,需要注意的是读取必须同写入的过程一一对应,即第一个写入 quint32 型的魔术数字,那么第一个读出的也必须是一个 quint32 格式的数据,如
  1. quint32 n;
  2. QImage p_w_picpath;
  3. QMap<QString, QColor> map;
  4. QFile file("facts.dat");
  5. if (!file.open(QIODevice::ReadOnly)) {
  6. std::cerr << "Cannot open file for reading: "
  7. << qPrintable(file.errorString()) << std::endl;
  8. return;
  9. }
  10. QDataStream in(&file);
  11. in.setVersion(QDataStream::Qt_4_3);
  12. in >> n >> p_w_picpath >> map;
好了,数据读出了,拿着到处去用吧!
这个 version 是干什么用的呢?对于二进制的读写,随着 Qt 的版本升级,可能相同的内容有了不同的读写方式,比如可能由大端写入变成了小端写入等,这样的话旧版本 Qt 写入的内容就不能正确的读出,因此需要设定一个版本号。比如这里我们使用 QDataStream::Qt_4_3,意思是,我们使用 Qt 4.3 的方式写入数据。实际上,现在的最高版本号已经是 QDataStream::Qt_4_6。如果这么写,就是说,4.3 版本之前的 Qt 是不能保证正确读写文件内容的。那么,问题就来了:我们以硬编码的方式写入这个 version,岂不是不能使用最新版的 Qt 的读写了?
解决方法之一是,我们不仅仅写入一个魔术数字,同时写入这个文件的版本。例如:
  1. QFile file("file.xxx");
  2. file.open(QIODevice::WriteOnly);
  3. QDataStream out(&file);
  4. // Write a header with a "magic number" and a version
  5. out << (quint32)0xA0B0C0D0;
  6. out << (qint32)123;
  7. out.setVersion(QDataStream::Qt_4_0);
  8. // Write the data
  9. out << lots_of_interesting_data;
这个 file.xxx 文件的版本号是 123。我们认为,如果版本号是123的话,则可以使用 Qt_4_0 版本读取。所以我们的读取代码就需要判断一下:
  1. QFile file("file.xxx");
  2. file.open(QIODevice::ReadOnly);
  3. QDataStream in(&file);
  4. // Read and check the header
  5. quint32 magic;
  6. in >> magic;
  7. if (magic != 0xA0B0C0D0)
  8. return XXX_BAD_FILE_FORMAT;
  9. // Read the version
  10. qint32 version;
  11. in >> version;
  12. if (version < 100)
  13. return XXX_BAD_FILE_TOO_OLD;
  14. if (version > 123)
  15. return XXX_BAD_FILE_TOO_NEW;
  16. if (version <= 110)
  17. in.setVersion(QDataStream::Qt_3_2);
  18. else
  19. in.setVersion(QDataStream::Qt_4_0);
  20. // Read the data
  21. in >> lots_of_interesting_data;
  22. if (version >= 120)
  23. in >> data_new_in_XXX_version_1_2;
  24. in >> other_interesting_data;
这样,我们就可以比较完美的处理二进制格式的数据读写了。

转载于:https://blog.51cto.com/devbean/293892

Qt学习之路(56): 二进制文件读写相关推荐

  1. 《Qt 学习之路 2》

    Home / Qt 学习之路 2 / <Qt 学习之路 2>目录 <Qt 学习之路 2>目录 序 Qt 前言 Hello, world! 信号槽 自定义信号槽 Qt 模块简介 ...

  2. QT学习之路2 学习笔记

    QT学习之路2 学习笔记 1.Qt 是一个著名的 C++ 应用程序框架.你并不能说它只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个&quo ...

  3. 转载: Qt 学习之路 2归档

    Qt 学习之路 2归档 http://www.devbean.net/2012/08/qt-study-road-2-catelog/

  4. 对QT学习之路12-14的源代码补充与修正

    QT学习之路12-14的源代码有些不完整,为了更好的让大家学习,本人做了一点修正与补充,谢谢.源代码如下: 头文件: #ifndef MAINWINDOW_H #define MAINWINDOW_H ...

  5. java qt gui_工控编程,Qt 学习之路

    原标题:工控编程,Qt 学习之路 Qt 是一个著名的 C++ 库--或许并不能说这只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI.使用 Qt,在一定程序上你获得的是一个"一站 ...

  6. Qt学习之路_12(简易数据管理系统)

    原文地址为: Qt学习之路_12(简易数据管理系统) 前言 最近从大陆来到台湾,之间杂事很多,挤不出时间来更新博客- 这次主要是通过做一个简易的数据库管理系统,来学习在Qt中对数据库,xml,界面的各 ...

  7. QT学习之路(一)ubuntu 18.04的Qt Creator在线安装

    文章目录 前言 一.准备工作 二.安装步骤 参考链接 前言 Qt是嵌入式开发的必备工具之一,在Linux下安装尤其重要. Qt是C++的一个库,或者说是开发框架,里面集成了一些库函数,提高开发效率. ...

  8. Qt学习之路(24): QPainter(改写paintEvent)

    Qt学习之路(24): QPainter(改写paintEvent) 多些大家对我的支持啊!有朋友也提出,前面的几节有关event的教程缺少例子.因为event比较难做例子,也就没有去写,只是把大概写 ...

  9. [记录]学习QT学习之路2第四天

    今天学习内容对应<<QT学习之路2>>第18到23部分,主要是有关于QT事件这一部分的内容(=_=真是看到我快吐了,感觉这本书不适合我这种初学者). 先放出思维导图 难点总结 ...

最新文章

  1. 华数机器人码垛_冲压机器人研究现状与发展方向
  2. wireshark 总体结构
  3. 海思芯片硬件java加速_海思Hi3719C V100芯片简介
  4. 每天一道LeetCode-----给定字符串s和字符数组words,在s中找到words出现的位置,words内部字符串顺序无要求
  5. 好程序员Java分享Java案例_英汉字典
  6. java this() super()_java中的this和super
  7. HDSF主要节点解说(二)工作原理
  8. C++析构函数与构造函数深拷贝浅拷贝(C++初学面向对象编程)
  9. myeclipse Could not create the view
  10. vue-cli3+cordova实现app混合开发
  11. 十进制到二进制的转换
  12. 程序员写文档工具推荐,让你爱上写文档!
  13. 百度地图获取行政区划边界
  14. 【MyEcplise】build workspace卡死
  15. libpcap简介及网络监测系统
  16. 系统平台补流量会影响店铺吗?
  17. mac 下安装swoole
  18. 计算机二级等级证书Java考试-模拟试题1
  19. 简单便签程序--青柠便签
  20. 报错:java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver at java.base/jdk.internal.loader.Bui

热门文章

  1. php数据仓库数据分析,利用Apache+PHP+MySql构建数据仓库
  2. ubuntu创建vim php文件,在ubuntu 上配置vim的php开发环境
  3. iOS12系统应用发送邮件中的附件
  4. John the Ripper
  5. list对象排序java_【Java】list对象(类)按某个属性排序
  6. 领域计算机控制系统分为,计算机测控系统概述
  7. 150名打工人被AI判定“效率低”遭开除,网友:属实是人工智能,能治工人
  8. 俄罗斯黑客收到500万美元赎金!美国燃油管道商认怂,民众为抢汽油大打出手...
  9. 擦掉纹身的AI火了:再现无暇皮肤,网友却发现“伏地魔” | Reddit热议
  10. 微软这次发布会巨硬:安卓折叠手机、双屏电脑,还有无线耳机和超薄平板