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

定长记录采用数据库读写并非最佳解决方案一文中,介绍了不管文件中记录数据为多少,只要按照文中介绍的方法存储,对于文件中任意1条记录数据,在读缓冲内存恒定不变的情况下,最多只需要读文件1次,而且定位记录的算法也超级简单,只需做1次除法运算和1次求余运算。今天我在这里介绍一下它的C++实现方法。

1.写记录

[cpp] view plain copy
 
  1. #ifndef _WRITE_RECORD_H  
  2. #define _WRITE_RECORD_H  
  3.   
  4. #include <qglobal.h>  
  5. #include <qfile.h>  
  6.   
  7. #define  INDEX_BLK_RECORD_NUM          1000  
  8. #define  RECORD_BLK_RECORD_NUM         1000  
  9. #define  MAGIC                         "BETTARECORD"  
  10. #define  MAGIC_LEN                     sizeof(MAGIC) - 1  
  11. #pragma pack(1)  
  12. typedef struct tagRecord {  
  13.     quint64 id;  
  14.     float cur;  
  15.     float vol;  
  16.     float tempe;  
  17.     float resistor;  
  18. } TRecord;  
  19.   
  20. typedef struct tagFileHead {  
  21.     quint8 magic[MAGIC_LEN];  
  22.     quint32 version;  
  23.     quint32 indexBlkNum;  
  24. } TFileHead;  
  25.   
  26. typedef struct tagBlkHead {  
  27.     quint64 nextBlkPos;  
  28.     quint32 recordNum;  
  29. }TBlkHead;  
  30.   
  31. typedef struct tagIndexBlk {  
  32.     TBlkHead head;  
  33.     quint32 blkAddr[INDEX_BLK_RECORD_NUM];  
  34. } TIndexBlk;  
  35.   
  36. typedef struct tagRecordBlk {  
  37.     TBlkHead blkHead;  
  38.     TRecord record[RECORD_BLK_RECORD_NUM];  
  39. } TRecordBlk;  
  40.   
  41. #pragma pack()  
  42. class CWriteRecord {  
  43.   
  44. public:  
  45.     CWriteRecord();  
  46.     ~CWriteRecord();  
  47.     bool openFile(const QString &fileName);  
  48.     void writeRecordHead(const TFileHead *pFileHead);  
  49.     void writeRecordBlk(const TRecord *pRecord);  
  50.     void flushBlk(bool bClose);  
  51.   
  52. private:  
  53.     void writeRecordBlkHead();  
  54.     void writeIndexBlk(quint64 blkPos);  
  55.     void writeIndexBlkNum();  
  56.     void writeIndexBlkHead();  
  57.     void init();  
  58.   
  59. private:  
  60.     QFile file;  
  61.   
  62.     TBlkHead indexBlkHead;  
  63.     TBlkHead recordBlkHead;  
  64.   
  65.     quint32 validIndexBlkRecordNum;  
  66.     quint32 validRecordBlkRecordNum;  
  67.   
  68.     quint32 indexBlkNum;  
  69.     quint32 validIndexBlkNum;  
  70.   
  71.     quint32 index;  
  72.     quint32 recordIndex;  
  73.   
  74.     quint64 indexBlkPos;  
  75.     quint64 recordBlkPos;  
  76.   
  77.     quint64 nextBlkPos;  
  78. };  
  79. #endif  

头文件提供了openFile,writeRecordHead,writeRecordBlk,flushBlk,四个公有接口,首先通过openFile打开一个文件,该文件可以是1个已存在的文件,也可以是1个不存在的文件,由fileName指定,openFile自动将文件初始化到就绪状态,打开以后,就可以使用writeRecordHead,writeRecordBlk,写记录了,flushBlk,是将文件flush到磁盘的操作,接下来我们看看实现:

[cpp] view plain copy
 
  1. #include "writerecord.h"  
  2. CWriteRecord::CWriteRecord()  
  3. {  
  4.   
  5. }  
  6.   
  7. CWriteRecord::~CWriteRecord()  
  8. {  
  9.   
  10. }  
  11.   
  12. bool CWriteRecord::openFile(const QString &fileName)  
  13. {  
  14.     if (file.isOpen())  
  15.         file.close();  
  16.     file.setFileName(fileName);  
  17.     return file.open(QIODevice::Append | QIODevice::ReadWrite);  
  18. }  
  19.   
  20. void CWriteRecord::writeRecordHead(const TFileHead *pFileHead)  
  21. {  
  22.     file.seek(0);  
  23.     file.write((const char *)pFileHead, sizeof(TFileHead));  
  24.     init();     
  25. }  
  26.   
  27.   
  28. void CWriteRecord::init()  
  29. {  
  30.     recordBlkHead.recordNum = 0;  
  31.     indexBlkHead.recordNum = 0;  
  32.     validIndexBlkRecordNum = 0;  
  33.     validRecordBlkRecordNum = 0;  
  34.       
  35.     indexBlkNum = 1;      
  36.     validIndexBlkNum = 0;  
  37.       
  38.     index = 0;  
  39.     recordIndex = 0;  
  40.       
  41.     indexBlkPos = sizeof(TFileHead);  
  42.     recordBlkPos = indexBlkPos + sizeof(TIndexBlk);  
  43.     nextBlkPos = recordBlkPos + sizeof(TRecordBlk);  
  44. }  
  45.   
  46. void CWriteRecord::writeRecordBlkHead()  
  47. {  
  48.     if (validRecordBlkRecordNum != recordBlkHead.recordNum  
  49.         && recordBlkHead.recordNum != 0)  
  50.     {  
  51.         validRecordBlkRecordNum = recordBlkHead.recordNum;  
  52.         file.seek(recordBlkPos);  
  53.         file.write((const char *)&recordBlkHead, sizeof(recordBlkHead));  
  54.         writeIndexBlk(recordBlkPos);  
  55.     }  
  56. }  
  57.   
  58. void CWriteRecord::writeRecordBlk(const TRecord *pRecord)  
  59. {  
  60.     quint64 writePos = recordBlkPos + recordIndex * sizeof(TRecord) + sizeof(TBlkHead);  
  61.     file.seek(writePos);  
  62.     file.write((const char *)pRecord, sizeof(TRecord));  
  63.   
  64.     recordIndex++;  
  65.     recordBlkHead.recordNum = recordIndex;  
  66.     if (recordIndex == RECORD_BLK_RECORD_NUM)  
  67.     {  
  68.         /*写当前块*/  
  69.         recordBlkHead.nextBlkPos = nextBlkPos;  
  70.         writeRecordBlkHead();  
  71.   
  72.         /*初始化下一块*/  
  73.         recordBlkHead.recordNum = 0;  
  74.         recordBlkPos = nextBlkPos;  
  75.         recordIndex = 0;  
  76.         recordBlkNum++;  
  77.   
  78.         nextBlkPos = nextBlkPos + sizeof(TRecordBlk);  
  79.     }  
  80. }  
  81.   
  82.   
  83. void CWriteRecord::writeIndexBlkHead()  
  84. {  
  85.     if (validIndexBlkRecordNum != indexBlkHead.recordNum  
  86.         && indexBlkHead.recordNum != 0)  
  87.     {  
  88.         validIndexBlkRecordNum = indexBlkHead.recordNum;  
  89.         file.seek(indexBlkPos);  
  90.         file.write((const char *)&indexBlkHead, sizeof(indexBlkHead));  
  91.         writeIndexBlkNum();  
  92.     }  
  93. }  
  94.   
  95. void CWriteRecord::writeIndexBlkNum()  
  96. {  
  97.     if (validIndexBlkNum != indexBlkNum)  
  98.     {  
  99.         validIndexBlkNum = indexBlkNum;  
  100.   
  101.         quint32 writePos = (quint32)&((TFileHead *)0)->indexBlkNum;  
  102.         file.seek(writePos);  
  103.         file.write((const char *)&indexBlkNum, sizeof(indexBlkNum));  
  104.     }  
  105. }  
  106.   
  107. void CWriteRecord::writeIndexBlk(quint64 blkPos)  
  108. {  
  109.     quint64 writePos = indexBlkPos + index * sizeof(TIndex) + sizeof(TBlkHead);  
  110.     file.seek(writePos);  
  111.     file.write((const char *)&blkPos, sizeof(blkPos));  
  112.   
  113.     index++;  
  114.     indexBlkHead.recordNum = index;  
  115.     quint32 blkRecordNum = INDEX_BLK_RECORD_NUM;  
  116.     if (index == blkRecordNum)  
  117.     {  
  118.         /*写当前块*/  
  119.         indexBlkHead.nextBlkPos = nextBlkPos;  
  120.         writeIndexBlkHead();  
  121.   
  122.         /*初始化下一块*/  
  123.         indexBlkHead.recordNum = 0;  
  124.         indexBlkPos = nextBlkPos;  
  125.         index = 0;  
  126.         indexBlkNum++;  
  127.   
  128.         nextBlkPos = nextBlkPos + sizeof(TIndexBlk);  
  129.     }  
  130. }  
  131.   
  132.   
  133. void CWriteRecord::flushBlk(bool bClose)  
  134. {  
  135.     if (file.isOpen())  
  136.     {  
  137.         writeIndexBlkHead();  
  138.         writeRecordBlkHead();  
  139.         if (bClose)  
  140.             file.close();  
  141.         else  
  142.             file.flush();  
  143.     }  
  144. }  


2.读记录

[cpp] view plain copy
 
  1. #ifndef _READ_RECORD_H  
  2. #define _READ_RECORD_H  
  3.   
  4. #include <qglobal.h>  
  5. #include <qfile.h>  
  6. class CReadRecord {  
  7.   
  8. public:  
  9.     static CReadRecord *getInstance();  
  10.     const TRecordBlk &readRecordBlk(quint64 blkPos);  
  11.     bool read(const QString &fileName);  
  12.     const QVector <quint64> *getRecordBlkPosList();  
  13.   
  14.   
  15. private:  
  16.     CReadRecord();  
  17.     void readRecordHead();  
  18.     void initBlkPosList();  
  19.   
  20. private:  
  21.     QFile file;  
  22.     TRecordBlk recordBlk;  
  23.     TIndexBlk indexBlk;  
  24.   
  25.     TFileHead fileHead;  
  26.     QVector <quint64> recordBlkPosList;  
  27.     static CReadRecord mSelf;  
  28. };  
  29. #endif  
[cpp] view plain copy
 
    1. #include "readrecord.h"  
    2. CReadRecord CReadRecord::mSelf;  
    3. CReadRecord *CReadRecord::getInstance()  
    4. {  
    5.     return &mSelf;  
    6. }  
    7.   
    8. CReadRecord::CReadRecord()  
    9. {  
    10.   
    11. }  
    12.   
    13. bool CReadRecord::read(const QString &fileName)  
    14. {  
    15.     if (file.isOpen())  
    16.         file.close();  
    17.     file.setFileName(fileName);  
    18.     if (!file.open(QIODevice::ReadOnly))  
    19.         return false;  
    20.     readRecordHead();  
    21.     if (memcmp(recordHead.magic,  
    22.                FILE_MAGIC,  
    23.                FILE_MAGIC_LEN) == 0)  
    24.     {  
    25.         initBlkPosList();  
    26.         return true;  
    27.     }  
    28.     return false;  
    29. }  
    30.   
    31. const QVector <quint64> *CReadRecord::getRecordBlkPosList()  
    32. {  
    33.     return &recordBlkPosList;  
    34. }  
    35.   
    36.   
    37. void CReadRecord::readRecordHead()  
    38. {  
    39.     file.seek(0);  
    40.     file.read((char *)&fileHead, sizeof(TFileHead));  
    41. }  
    42.   
    43.   
    44. const TRecordBlk &CReadRecord::readRecordBlk(quint64 blkPos)  
    45. {  
    46.     readFile(blkPos, (quint8 *)&recordBlk, sizeof(recordBlk));  
    47.     return recordBlk;  
    48. }  
    49.   
    50. void CReadRecord::initBlkPosList()  
    51. {  
    52.     recordBlkPosList.clear();  
    53.     int cnt = fileHead.indexBlkNum;  
    54.     quint64 indexBlkPos = sizeof(TFileHead);  
    55.     for (int i = 0; i < cnt; i++)  
    56.     {  
    57.         readFile(indexBlkPos, (quint8 *)&indexBlk, sizeof(indexBlk));  
    58.         int cnt1 = indexBlk.blkHead.recordNum;  
    59.         for (int j = 0; j < cnt1; j++)  
    60.         {  
    61.             recordBlkPosList.append(indexBlk.index[j]);  
    62.         }  
    63.         indexBlkPos = indexBlk.blkHead.nextBlkPos;  
    64.     }  
    65. }  

http://blog.csdn.net/rabinsong/article/details/8957825

posted @ 2016-06-25 05:17  findumars  Views(564)  Comments(0Edit  收藏  举报