【问题标题】:'Good' programming form in maintaining / updating / accessing files by entry通过条目维护/更新/访问文件的“良好”编程形式
【发布时间】:2012-12-20 06:26:16
【问题描述】:

基本问题:

如果我正在记录/修改数据,我是否应该通过索引硬编码索引访问文件的元素,即targetFile.getElement(5);通过硬编码标识符(内部转换为索引),即target.getElementWithID("Desired Element"),或带有一些中间的DESIRED_ELEMENT = 5; ... target.getElement(DESIRED_ELEMENT),等等。

编辑:或者使用enum ??


背景:

我的程序 (c++) 将数据存储在许多不同的 'dataFile's 中。我还在 another 文件中保留了所有数据文件的列表——一个 'listFile'——它还存储了每个文件的一些属性(见下文,但即它的名称是什么,它有多少行信息等)。有一个对象管理数据文件和列表文件,称之为'fileKeeper'

listFile 的条目类似于:

filename , contents name , number of lines , some more numbers ...

我绝对有可能从这个列表中添加/删除字段 --- 但一般来说,它们会保持静态。

现在,我有一个常量字符串数组,它保存每个条目中每个元素的标识,例如:

const string fileKeeper::idKeys[] = { "FileName" , "Contents" , "NumLines" ... };
const int fileKeeper::idKeysNum = 6;   // 6 - for example

我正在尝试以“良好”的程序形式管理这些东西。因此,当我想检索文件中的行数时(例如),而不是使用仅检索“3”元素的方法...相反,我会执行以下操作:

string desiredID = "NumLines";
int desiredIndex = indexForID(desiredID);
string desiredElement = elementForIndex(desiredIndex);

函数indexForID() 遍历idKeys 的条目直到找到desiredID 然后返回它对应的索引。而elementForIndex(index) 实际上进入 listFile 以检索逗号分隔字符串的第 index 个元素。


问题:

这看起来仍然很丑/糟糕的形式。有一种我应该这样做的方式吗?如果不是,通常有哪些一般的方法?

谢谢!

【问题讨论】:

  • 这似乎是 list 而不是您需要组织的 tabular 数据。 IE。您想通过键访问完整的字符串,而不是像数据库中那样的表的单独字段。因此,您必须根据数据访问的类型选择最合适的结构。如果您经常插入/删除,它可以是 std::list ,或者在大多数情况下您需要访问某个键时它可以是字符串的 std::vector ,或者它可以是 CodeChords 人建议的 std::map 如果您想访问单独的字段。最后,按照 Karthik T 的建议在课堂上组织它。

标签: c++ c database record


【解决方案1】:

我喜欢使用字符串作为键的方式。您可以使用std::map<string, int> 将字符串映射到数字。然后你可以做

std::map<string, int> columns;
columns["FileName"] = 0;    
columns["Contents"] = 1;
columns["NumLines"] = 2;

然后您可以参考columns["Contents"],例如,获取列ID。最好是通过一个函数来完成,如果你拼错了一个键,它会通知你。像这样的一些代码:

std::map<string, int>::iterator it = columns.find(key);
if (it == columns.end()) { // key not in columns
    // report error here

【讨论】:

  • 这与使用枚举有什么不同,即enum Keys { FileName, Contents, NumLines }——在这种情况下,它们已经映射到0, 1, 2
【解决方案2】:

不要使用数据库或至少使用 csv。 Sqlite 是一个轻量级、无服务器的数据库,并且几乎可以使用任何语言进行绑定。它专为这种需要存储大量数据但又不想安装和配置数据库服务器的场景而设计。您可能还想创建一个结构/类来保存数据,可能需要某种 ORM 的帮助。

如果您使用 csv 并且希望能够重新排列列顺序,请将列名保存为文件的第一个条目,大多数 csv 库应该能够使用第一列作为列名。

【讨论】:

    【解决方案3】:

    首先创建一个FileProperty 类,listFile 将是此类的对象列表,而您的“键”将是此类的成员变量。

    【讨论】:

      【解决方案4】:

      我的解决方案是结合使用 std::map 和枚举:

      class FileKeeper {
          public:
              enum ID_KEY = { FileName , Contents , "Num_Lines };
              string getIDKey(ID_KEY idk);
      
          private:
              static map<int,string> ID_Key = { { FileName, "Filename" }, { Contents, "Contents" }, { Num_Lines, "Num Lines" } };
      
      }
      
      string FileKeeper::getIDKey(ID_KEY idk) {
          if( idk > 0 && idk < ID_Key.size() ) { return ID_Key[idk]; }
          else { return ""; }
      }
      

      通过这种方式,我可以使用枚举轻松访问索引并轻松遍历键(以正确的顺序 --- map&lt;string,int&gt; 不会这样做),并且仍然使用枚举检索从索引到字符串的映射地图。使用get() 方法可以防止向地图添加元素,并且保持实际的map 私有可以防止我使用整数懒惰地访问它(即使它在技术上是int-index 类型)。

      我不需要在代码中的哪个位置使用已识别的实际字符串访问元素,即 get___("Num Lines"); --- 这有点难看,似乎是一个失礼

      【讨论】:

        猜你喜欢
        • 2010-09-12
        • 2012-09-22
        • 2012-02-07
        • 1970-01-01
        • 2015-08-11
        • 2015-03-14
        • 1970-01-01
        • 2013-09-11
        • 1970-01-01
        相关资源
        最近更新 更多