-3

考虑以下文件内容

[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++ 更改该频道的某些属性。关键是每个通道的属性都写在“通道”关键字上方。例如,我需要将频道 5 的上下文属性更改为电话。我该怎么做?

编辑:

所以我终于找到了办法。我逐行读取文件,寻找“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;
}
4

1 回答 1

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,如前面的示例中使用的那样)的方法) 并且可以读取该对象并将其值转换为您的文件格式。在没有实际为您编写解析器和编写器的情况下,这可能是我可以解释它的最佳方式。

于 2013-09-23T14:27:08.507 回答