考虑以下文件内容
[channels]
usecallerid=yes
cidsignalling=dtmf
cidstart=dtmf
;group=0
usecallerid=yes
context=pstn-channels
channel=>5
;group=0
usecallerid=yes
context=pstn-channels
channel=>6
;group=0
usecallerid=yes
context=pstn-channels
channel=>7
;group=1
context=phone-channels
channel=>1-4
我只是想搜索一个频道,用c ++改变该频道的一些属性。关键是每个通道的属性都写在“channel”关键字之上。 例如,我需要将频道5的上下文属性更改为phone。 我怎么能这样做?
编辑:
所以我终于找到了办法。我逐行读取文件,查找“group”关键字,在到达此关键字后,我开始将每一行推回到字符串向量,直到我到达包含“channel”关键字的行。然后我用“=”分隔符分割最后一行并将单元格号1与“portNumber”进行比较,然后如果它们匹配,我搜索字符串向量(以“group”开头并以“channel”关键字结束的数据块)对于用户想要更改它的属性,在找到此属性后,我计算适当的偏移量以使用seekg函数更改文件的指针位置,然后我写入数据。 但事情是每条线都有有限数量的字符,即在插入较长线的情况下,其他线错过了。考虑下面的第三行块
;group=0
usecallerid=yes
context=pstn-channels
channel=>131
如果我想将此行更改为“context = phone-channels”,结果将为
;group=0
usecallerid=n
context=phone-channels
channel=>130
你可以看到第二行得到了错误的值。我认为在编辑之前在每行的末尾添加一些空格会很有用,但是我觉得这不是一个有效的解决方案。所以你怎么看?我希望你能清楚问题和问题......
这是代码
bool changeConfigFiles(string addr, int portNumber, string key, string value)
{
//
char cmd[200];
fstream targetFile(addr.c_str());
string lines;
int offset=0,pPosition;
vector<string> helper,anotherHelper;
vector<string> contentsBlock;
//
if (!targetFile.is_open())
{
return false;
}
//
while(getline(targetFile, lines))
{
if(lines.find("group") != string::npos)
{
pPosition = targetFile.tellg();
pPosition -= lines.length();
contentsBlock.push_back(lines);
while(getline(targetFile, lines))
{
if(lines.find("=>") != string::npos)
{
helper = explode("=>",lines);
contentsBlock.push_back(lines);
break;
}
contentsBlock.push_back(lines);
}
}
//
if(helper.size() !=0 && strToInt(helper[1]) == portNumber)
{
for(int i=0;i<contentsBlock.size();i++)
{
if(contentsBlock[i].find(key) != string::npos)
{
anotherHelper = explode("=",contentsBlock[i]);
targetFile.seekg(pPosition+offset-1);
targetFile << endl << anotherHelper[0] << "=" << value << endl;
}
offset += contentsBlock[i].length();
}
//
helper.clear();
targetFile.seekg(pPosition+offset);
}
contentsBlock.clear();
}
targetFile.close();
return true;
}
答案 0 :(得分:0)
假设您拥有此文件的已知数据布局,我将回答这个问题,好像它是“我如何解析此文件”问题。在C ++中,fstream是一种原生解析文件的简单方法。请考虑以下内容(假设您有一个字符串拆分和一个字符串IndexOf方法,这两个方法都非常容易编写):
char** SplitString( _In_ char* string, _In_ char token, _Out_ int* tokenCount );
int IndexOf( _In_ char* string, _In_ char* search, _Out_ int* count, _Out_ int length );
CustomFileType* ParseFile( char* filename )
{
int bufferSize = 10000;
auto buffer = new char[ bufferSize];
memset( buffer, 0, bufferSize);
ifstream file( filename );
file.read( buffer, bufferSize );
file.close( );
int blockCount = 0;
auto blocks = SplitString( buffer, ';', &blockCount );
CustomFileType* file = new CustomFileType( );
for( int blockIndex = 0; blockIndex < blockCount; blockIndex++ )
{
Block* b = new Block( );
b.PropertyX = GetValueOf( buffer, "PropertyX=" );
b.PropertyY = GetValueOf( buffer, "PropertyY=" );
file.Blocks.Add( b );
}
}
char* GetValueOf( char* buffer, char* key )
{
int count = 0;
int length = 0;
int index = IndexOf( buffer, key, &count, &length );
if( length == 0 || count == 0 ) return nullptr;
auto output = new char[ length ];
memcpy( output, &buffer[ index ], length );
return output;
}
这大致涵盖了解析的想法。将文件分成块,读取每个块的每个元素,检索与每个键相关的每个值,转换为数据类型(上面未显示)并分配给相关属性。
要更改文件的值,您可以简单地(我称之为)解析它,将数据结构转换回其格式。因此,使用解析器读取对象,更改值,然后解析它(或对其进行编码,无论您喜欢哪个术语)。
要更改值并将其写回文件,请考虑手头的实际问题。您已将文本解析为对象,并且您知道文件格式。所以现在需要替换对象上的值并将它们写回文件。您的文件结构看起来遵循以下格式:
[标题信息]
[组]
其中组以分号分隔,并且标题信息和组都由键值对(x = y)的集合定义。所以说,你需要一个知道如何编写键值对的方法(这应该是微不足道的),然后是另一个理解标题/组布局的方法,并且可以接受一个对象(可能是CustomFileType,如前面的例子所用)并且可以读取该对象并将其值转换为您的文件格式。如果没有为你编写解析器和编写器,这可能是我解释它的最好方法。