'Good'通过条目维护/更新/访问文件的编程形式

'Good' programming form in maintaining / updating / accessing files by entry

本文关键字:文件 访问 编程 维护 Good 更新      更新时间:2023-10-16

基本问题:

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

编辑:或者使用enum??


背景:

我的程序(c++)将数据存储在许多不同的'dataFile中。我还将所有数据文件的列表保存在另一个文件中——一个"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"d元素的方法。。。相反,我做了一些类似的事情:

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

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


问题:

这看起来仍然很丑陋/糟糕的形式。有没有我应该这样做?如果没有,通常有哪些通用方法?

谢谢!

我喜欢使用字符串作为键的方式。可以使用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

两者都不使用,使用数据库或至少使用csv。Sqlite是一个轻量级、无服务器的数据库,绑定几乎可以用任何语言提供。它正是为这种情况而设计的,在这种情况下,您需要存储大量数据,但不想安装和配置数据库服务器。您可能还想创建一个结构/类来保存数据,也许可以借助某种ORM。

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

首先创建一个FileProperty类,listFile将是该类的对象列表,您的"Keys"将是该类别的成员变量。

我的解决方案使用std::map和enum:的组合

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<string,int>不会这样做),并且仍然可以使用映射检索从索引到字符串的映射。使用get()方法可以防止向映射中添加元素,而保持实际的map私有可以防止我使用整数懒惰地访问它(即使它在技术上是int索引类型)。

在代码中的任何位置,我都不需要使用已标识的实际字符串访问元素,即get___("Num Lines");---这有点丑陋,似乎是一种失礼