zoukankan      html  css  js  c++  java
  • 简单高效的分块记录的实现

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

  • 相关阅读:
    程序员要善于在工作中找到偷懒的办法
    关于count(1) 和 count(*)
    前端设计+程序开发那点事
    关于MySQL Connector/C++那点事儿
    windows下编译php5.2.17这是闹哪样?
    easyui使用时出现这个Uncaught TypeError: Cannot read property 'combo' of undefined
    视频文件自动转rtsp流
    Jenkins Pipeline如何动态的并行任务
    Jenkins的Dockerfile中如何批量迁移原Jenkins安装的插件
    Groovy中json的一些操作
  • 原文地址:https://www.cnblogs.com/findumars/p/5615724.html
Copyright © 2011-2022 走看看