简单高效的分块记录的实现
在定长记录采用数据库读写并非最佳解决方案一文中,介绍了不管文件中记录数据为多少,只要按照文中介绍的方法存储,对于文件中任意1条记录数据,在读缓冲内存恒定不变的情况下,最多只需要读文件1次,而且定位记录的算法也超级简单,只需做1次除法运算和1次求余运算。今天我在这里介绍一下它的C++实现方法。
1.写记录
- #ifndef _WRITE_RECORD_H
- #define _WRITE_RECORD_H
- #include <qglobal.h>
- #include <qfile.h>
- #define INDEX_BLK_RECORD_NUM 1000
- #define RECORD_BLK_RECORD_NUM 1000
- #define MAGIC "BETTARECORD"
- #define MAGIC_LEN sizeof(MAGIC) - 1
- #pragma pack(1)
- typedef struct tagRecord {
- quint64 id;
- float cur;
- float vol;
- float tempe;
- float resistor;
- } TRecord;
- typedef struct tagFileHead {
- quint8 magic[MAGIC_LEN];
- quint32 version;
- quint32 indexBlkNum;
- } TFileHead;
- typedef struct tagBlkHead {
- quint64 nextBlkPos;
- quint32 recordNum;
- }TBlkHead;
- typedef struct tagIndexBlk {
- TBlkHead head;
- quint32 blkAddr[INDEX_BLK_RECORD_NUM];
- } TIndexBlk;
- typedef struct tagRecordBlk {
- TBlkHead blkHead;
- TRecord record[RECORD_BLK_RECORD_NUM];
- } TRecordBlk;
- #pragma pack()
- class CWriteRecord {
- public:
- CWriteRecord();
- ~CWriteRecord();
- bool openFile(const QString &fileName);
- void writeRecordHead(const TFileHead *pFileHead);
- void writeRecordBlk(const TRecord *pRecord);
- void flushBlk(bool bClose);
- private:
- void writeRecordBlkHead();
- void writeIndexBlk(quint64 blkPos);
- void writeIndexBlkNum();
- void writeIndexBlkHead();
- void init();
- private:
- QFile file;
- TBlkHead indexBlkHead;
- TBlkHead recordBlkHead;
- quint32 validIndexBlkRecordNum;
- quint32 validRecordBlkRecordNum;
- quint32 indexBlkNum;
- quint32 validIndexBlkNum;
- quint32 index;
- quint32 recordIndex;
- quint64 indexBlkPos;
- quint64 recordBlkPos;
- quint64 nextBlkPos;
- };
- #endif
头文件提供了openFile,writeRecordHead,writeRecordBlk,flushBlk,四个公有接口,首先通过openFile打开一个文件,该文件可以是1个已存在的文件,也可以是1个不存在的文件,由fileName指定,openFile自动将文件初始化到就绪状态,打开以后,就可以使用writeRecordHead,writeRecordBlk,写记录了,flushBlk,是将文件flush到磁盘的操作,接下来我们看看实现:
- #include "writerecord.h"
- CWriteRecord::CWriteRecord()
- {
- }
- CWriteRecord::~CWriteRecord()
- {
- }
- bool CWriteRecord::openFile(const QString &fileName)
- {
- if (file.isOpen())
- file.close();
- file.setFileName(fileName);
- return file.open(QIODevice::Append | QIODevice::ReadWrite);
- }
- void CWriteRecord::writeRecordHead(const TFileHead *pFileHead)
- {
- file.seek(0);
- file.write((const char *)pFileHead, sizeof(TFileHead));
- init();
- }
- void CWriteRecord::init()
- {
- recordBlkHead.recordNum = 0;
- indexBlkHead.recordNum = 0;
- validIndexBlkRecordNum = 0;
- validRecordBlkRecordNum = 0;
- indexBlkNum = 1;
- validIndexBlkNum = 0;
- index = 0;
- recordIndex = 0;
- indexBlkPos = sizeof(TFileHead);
- recordBlkPos = indexBlkPos + sizeof(TIndexBlk);
- nextBlkPos = recordBlkPos + sizeof(TRecordBlk);
- }
- void CWriteRecord::writeRecordBlkHead()
- {
- if (validRecordBlkRecordNum != recordBlkHead.recordNum
- && recordBlkHead.recordNum != 0)
- {
- validRecordBlkRecordNum = recordBlkHead.recordNum;
- file.seek(recordBlkPos);
- file.write((const char *)&recordBlkHead, sizeof(recordBlkHead));
- writeIndexBlk(recordBlkPos);
- }
- }
- void CWriteRecord::writeRecordBlk(const TRecord *pRecord)
- {
- quint64 writePos = recordBlkPos + recordIndex * sizeof(TRecord) + sizeof(TBlkHead);
- file.seek(writePos);
- file.write((const char *)pRecord, sizeof(TRecord));
- recordIndex++;
- recordBlkHead.recordNum = recordIndex;
- if (recordIndex == RECORD_BLK_RECORD_NUM)
- {
- /*写当前块*/
- recordBlkHead.nextBlkPos = nextBlkPos;
- writeRecordBlkHead();
- /*初始化下一块*/
- recordBlkHead.recordNum = 0;
- recordBlkPos = nextBlkPos;
- recordIndex = 0;
- recordBlkNum++;
- nextBlkPos = nextBlkPos + sizeof(TRecordBlk);
- }
- }
- void CWriteRecord::writeIndexBlkHead()
- {
- if (validIndexBlkRecordNum != indexBlkHead.recordNum
- && indexBlkHead.recordNum != 0)
- {
- validIndexBlkRecordNum = indexBlkHead.recordNum;
- file.seek(indexBlkPos);
- file.write((const char *)&indexBlkHead, sizeof(indexBlkHead));
- writeIndexBlkNum();
- }
- }
- void CWriteRecord::writeIndexBlkNum()
- {
- if (validIndexBlkNum != indexBlkNum)
- {
- validIndexBlkNum = indexBlkNum;
- quint32 writePos = (quint32)&((TFileHead *)0)->indexBlkNum;
- file.seek(writePos);
- file.write((const char *)&indexBlkNum, sizeof(indexBlkNum));
- }
- }
- void CWriteRecord::writeIndexBlk(quint64 blkPos)
- {
- quint64 writePos = indexBlkPos + index * sizeof(TIndex) + sizeof(TBlkHead);
- file.seek(writePos);
- file.write((const char *)&blkPos, sizeof(blkPos));
- index++;
- indexBlkHead.recordNum = index;
- quint32 blkRecordNum = INDEX_BLK_RECORD_NUM;
- if (index == blkRecordNum)
- {
- /*写当前块*/
- indexBlkHead.nextBlkPos = nextBlkPos;
- writeIndexBlkHead();
- /*初始化下一块*/
- indexBlkHead.recordNum = 0;
- indexBlkPos = nextBlkPos;
- index = 0;
- indexBlkNum++;
- nextBlkPos = nextBlkPos + sizeof(TIndexBlk);
- }
- }
- void CWriteRecord::flushBlk(bool bClose)
- {
- if (file.isOpen())
- {
- writeIndexBlkHead();
- writeRecordBlkHead();
- if (bClose)
- file.close();
- else
- file.flush();
- }
- }
2.读记录
- #ifndef _READ_RECORD_H
- #define _READ_RECORD_H
- #include <qglobal.h>
- #include <qfile.h>
- class CReadRecord {
- public:
- static CReadRecord *getInstance();
- const TRecordBlk &readRecordBlk(quint64 blkPos);
- bool read(const QString &fileName);
- const QVector <quint64> *getRecordBlkPosList();
- private:
- CReadRecord();
- void readRecordHead();
- void initBlkPosList();
- private:
- QFile file;
- TRecordBlk recordBlk;
- TIndexBlk indexBlk;
- TFileHead fileHead;
- QVector <quint64> recordBlkPosList;
- static CReadRecord mSelf;
- };
- #endif
- #include "readrecord.h"
- CReadRecord CReadRecord::mSelf;
- CReadRecord *CReadRecord::getInstance()
- {
- return &mSelf;
- }
- CReadRecord::CReadRecord()
- {
- }
- bool CReadRecord::read(const QString &fileName)
- {
- if (file.isOpen())
- file.close();
- file.setFileName(fileName);
- if (!file.open(QIODevice::ReadOnly))
- return false;
- readRecordHead();
- if (memcmp(recordHead.magic,
- FILE_MAGIC,
- FILE_MAGIC_LEN) == 0)
- {
- initBlkPosList();
- return true;
- }
- return false;
- }
- const QVector <quint64> *CReadRecord::getRecordBlkPosList()
- {
- return &recordBlkPosList;
- }
- void CReadRecord::readRecordHead()
- {
- file.seek(0);
- file.read((char *)&fileHead, sizeof(TFileHead));
- }
- const TRecordBlk &CReadRecord::readRecordBlk(quint64 blkPos)
- {
- readFile(blkPos, (quint8 *)&recordBlk, sizeof(recordBlk));
- return recordBlk;
- }
- void CReadRecord::initBlkPosList()
- {
- recordBlkPosList.clear();
- int cnt = fileHead.indexBlkNum;
- quint64 indexBlkPos = sizeof(TFileHead);
- for (int i = 0; i < cnt; i++)
- {
- readFile(indexBlkPos, (quint8 *)&indexBlk, sizeof(indexBlk));
- int cnt1 = indexBlk.blkHead.recordNum;
- for (int j = 0; j < cnt1; j++)
- {
- recordBlkPosList.append(indexBlk.index[j]);
- }
- indexBlkPos = indexBlk.blkHead.nextBlkPos;
- }
- }
http://blog.csdn.net/rabinsong/article/details/8957825