• 程序设计:C++ 一个用目录结构构建索引的类


            有时候可以利用文件系统目录结构对数据进行索引,将数据存储为小文件,避免在大文件里搜索。文件系统的目录结构本身是个树结构,相当于索引树,但每个目录下的文件数不能太多,因为目录下文件是遍历查找的,同时也不能太少,因为每个目录节点本身也要占用空间,海量目录占用空间巨大。

            本代码用字符串做key,若干个字节放一级目录(参数设置),如果设置为一个字节一级目录,那么key="123"的数据放置在“1/2/3/123.cache”文件里。

            代码如下:

    1. //快速文件索引,此结构本身可以放在共享内存
    2. class CFastFileInex
    3. {
    4. private:
    5. sstring<256> m_dir;//根目录
    6. long section;//几个字节一层目录,同一个目录下文件超过一定数量打开文件会很慢
    7. public:
    8. char const * GetRoot()const { return m_dir.c_str(); }
    9. string & toString(string & str)const
    10. {
    11. stringstream ss;
    12. ss << "dir[" << m_dir.c_str() << "]" << section;
    13. return str = ss.str();
    14. }
    15. void SetFastFileInex(char const * dir, long _section)
    16. {
    17. m_dir = dir;
    18. section = _section;
    19. }
    20. string & ffiGetFileName(unsigned long key, string & filename)const
    21. {
    22. char buf[256];
    23. sprintf(buf, "%lu", key);
    24. return ffiGetFileName(buf, filename);
    25. }
    26. string & ffiGetFileName(char const * key, string & filename)const
    27. {
    28. filename = m_dir.c_str();
    29. int len = strlen(key);
    30. long k = len / section;
    31. if (0 == len % section)--k;
    32. for (long i = 0; i < k; ++i)
    33. {
    34. for (long j = 0; j < section; ++j) filename += key[i*section + j];
    35. filename += '/';
    36. }
    37. filename += key;
    38. filename += ".cache";
    39. return filename;
    40. }
    41. bool ffiReadFile(unsigned long key, CBuffer & buffer)const
    42. {
    43. char buf[256];
    44. sprintf(buf, "%lu", key);
    45. return ffiReadFile(buf, buffer);
    46. }
    47. bool ffiReadFile(char const * key, CBuffer & buffer)const
    48. {
    49. string filename;
    50. ffiGetFileName(key, filename);
    51. //打开失败再创建目录,再次打开失败才算失败
    52. CEasyFile file;
    53. if (!file.ReadFile(filename.c_str(), buffer))
    54. {
    55. CDir::CreateDir(filename.c_str());
    56. if (!file.ReadFile(filename.c_str(), buffer))
    57. {
    58. DEBUG_LOG << "打开文件出错 " << filename << " " << strerror(errno) << ende;
    59. return false;
    60. }
    61. }
    62. return true;
    63. }
    64. //读不到足够数据则失败
    65. bool ffiReadFile(long key, char * buffer, long buffersize)const
    66. {
    67. char buf[256];
    68. sprintf(buf, "%lu", key);
    69. return ffiReadFile(buf, buffer, buffersize);
    70. }
    71. //读不到足够数据则失败
    72. bool ffiReadFile(char const * key, char * buffer, long buffersize)const
    73. {
    74. string filename;
    75. ffiGetFileName(key, filename);
    76. //打开失败再创建目录,再次打开失败才算失败
    77. CEasyFile file;
    78. if (!file.ReadFile(filename.c_str(), buffer, buffersize))
    79. {
    80. CDir::CreateDir(filename.c_str());
    81. if (!file.ReadFile(filename.c_str(), buffer, buffersize))
    82. {
    83. DEBUG_LOG << "打开文件出错 " << filename << " " << strerror(errno) << ende;
    84. return false;
    85. }
    86. }
    87. return true;
    88. }
    89. bool ffiWriteFile(long key, char const * buffer, long buffersize)const
    90. {
    91. char buf[256];
    92. sprintf(buf, "%lu", key);
    93. return ffiWriteFile(buf, buffer, buffersize);
    94. }
    95. bool ffiWriteFile(char const * key, char const * buffer, long buffersize)const
    96. {
    97. string filename;
    98. ffiGetFileName(key, filename);
    99. //打开失败再创建目录,再次打开失败才算失败
    100. CEasyFile file;
    101. if (!file.WriteFile(filename.c_str(), buffer, buffersize))
    102. {
    103. CDir::CreateDir(filename.c_str());
    104. if (!file.WriteFile(filename.c_str(), buffer, buffersize))
    105. {
    106. DEBUG_LOG << "写入文件出错 " << filename << " " << strerror(errno) << ende;
    107. return false;
    108. }
    109. }
    110. return true;
    111. }
    112. bool ffiDeleteFile(long key)const
    113. {
    114. char buf[256];
    115. sprintf(buf, "%lu", key);
    116. return ffiDeleteFile(buf);
    117. }
    118. bool ffiDeleteFile(char const * key)const
    119. {
    120. string filename;
    121. ffiGetFileName(key, filename);
    122. //打开失败再创建目录,再次打开失败才算失败
    123. CEasyFile file;
    124. if (!file.DeleteFile(filename.c_str()))
    125. {
    126. DEBUG_LOG << "删除文件出错 " << filename << " " << strerror(errno) << ende;
    127. return false;
    128. }
    129. return true;
    130. }
    131. };

            里面用到的一些别的代码:

    sstring 是个定长字符串模板类,替换成string就可以了

    CDir 目录操作类,用到的函数的功能看名字就能理解了

    CEasyFile 一个简单的文件接口类,用到的函数的功能看名字就能理解了

    (这里是结束)

  • 相关阅读:
    C陷阱与缺陷 第3章 语义“陷阱” 3.6 边界计算与不对称边界
    C++入门教程(十、联合体)
    一文彻底弄懂Linux-Shell编程
    [CISCN2019 华东南赛区]Web11
    数据结构与算法:数据结构基础
    SpringBoot系统搭建集成-RabbitMq延时队列
    #816 Div2E. Long Way Home 斜率优化dp
    Perl 中的模式匹配修饰符
    2023-09-25 LeetCode每日一题(LFU 缓存)
    基于PBS向超算服务器队列提交任务的脚本模板与常用命令
  • 原文地址:https://blog.csdn.net/2301_77171572/article/details/133948619