简单高效的分块记录的实现

定长记录采用数据库读写并非最佳解决方案一文中,介绍了不管文件中记录数据为多少,只要按照文中介绍的方法存储,对于文件中任意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;
    }
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RabinSong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值