zoukankan      html  css  js  c++  java
  • fscanf读取INI文件时键名部分重合问题

    公司以前的项目中有的是用fscanf来读取INI文件,这会产生不少问题,键名部分重合便是一个不常出现,但可能出现的问题。

    这里指的键名部分重合是指在同一节(Section)中,键名间出现类似如下情况:

    NameAltitude=100
    Sort=10
    NameOffsetY=20

    以上3个字段均是可选项,其中NameAltitude和NameOffsetY的第一个单词出现了重合。NameOffsetY是后来功能需要再添加上去。使用fscanf读取INI文件数据相关代码如下:

    bool bSucRead = true;

    // ...
    // ...
    // ...

    // 读取必选键值-Begin
    bSucRead &= fscanf(fp, "Name=%s\n", pInfo->szName);
    bSucRead &= fscanf(fp, "SizeAdd=%d\n", &pInfo->nSizeAdd);
    // ...
    // ...
    // ...
    // 读取必选键值-End

    // 读取可选键值-Begin
    // ...
    // ...
    // ...
    if (!fscanf(fp, "NameAltitude=%d\n", &pInfo->nNameAltitude))
    {
        pInfo->nNameAltitude = 0;
    }

    if (!fscanf(fp, "Sort=%d\n", &pInfo->nSort))
    {
        pInfo->nSort = 0;
    }

    if (!fscanf(fp, "NameOffsetY=%d\n", &pInfo->nNameOffsetY))
    {
        pInfo->nNameOffsetY = 0;
    }
    // ...
    // ...
    // ...
    // 读取可选键值-End

    当有NameOffsetY前面至少有NameAltitude存在时,如下:

    [003]
    Name=monster
    SizeAdd=23
    ...
    ...
    ...
    NameAltitude=123
    Sort=14
    NameOffsetY=20

    或者

    [022]
    Name=monster
    SizeAdd=23
    ...
    ...
    ...
    NameAltitude=123
    NameOffsetY=20

    此时数据读取正常。

    而当从NameAltitude到NameOffsetY之前的字段都不存在时,如下:

    [041]
    Name=monster
    SizeAdd=23
    ...
    ...
    ...
    NameOffsetY=25

    NameOffsetY读取失败,pInfo->nNameOffsetY被赋予默认值0,而不是25。

    当文件指针走到"NameOffsetY"前时,fscanf却在准备读取"NameAltitude",结果前面的"Name"被读取了,然而到后面才发现读取错误,但文件指针已经走到"Altitude"前了。fscanf继续往后判断,读取"NameOffsetY"必然是失败的,因此pInfo->nNameOffsetY被赋予默认值0。

    解决方案一:使用GetPrivateProfileInt、GetPrivateProfileInt等WIN32 API函数来读取INI文件。

    解决方案二:使用现有框架下的CMyIni读取INI文件。

    解决方案三:在发现读取错误后,让文件指针退会正确位置,可使用ftell和fseek来实现:

    // 调整文件指针位置
    inline bool AdjustFilePtrPos(FILE* fp, long lPosBeforeOffset)
    {
        if (NULL != fp)
        {
            long lOffset = ftell(fp) - lPosBeforeOffset;
            if (0 < lOffset)
            {
                fseek(fp, -lOffset, SEEK_CUR);
                return true;
            }
        }
        return false;
    }

    //....
    //....
    //....
    long lPosBeforeOffset = ftell(fp); // 记录文件指针出错前位置
    if (!fscanf(fp, "NameAltitude=%d\n", &pInfo->nNameAltitude))
    {
        pInfo->nNameAltitude = 0;
        AdjustFilePtrPos(fp, lPosBeforeOffset); // 调整文件指针位置
    }
    //....
    //....
    //....

  • 相关阅读:
    SQL 学习随笔
    hibernate查询方式总结基于原生SQL查询(二)
    hibernate查询方式总结(四)之QBC,QBE查询
    Hibernate查询方式汇总之Hql查询(三)
    java 强引用,软引用,弱引用,虚引用
    JAVA-对java平台的理解
    Git SSH本机配置
    Windows下Python3解决 Microsoft Visual C++ 14.0 is required 报错
    checkpoint原理剖析与源码分析
    CacheManager原理剖析与源码分析
  • 原文地址:https://www.cnblogs.com/wxxweb/p/2246508.html
Copyright © 2011-2022 走看看