1. 程式人生 > >有關fgetc配合feof逐行讀取文件最後OA現金盤平臺出租一行讀取兩遍的錯覺

有關fgetc配合feof逐行讀取文件最後OA現金盤平臺出租一行讀取兩遍的錯覺

重復讀取 讀取文件 conf for 判斷 pass start 緩存 超出

有關fgetc配合feof逐行讀取文件最後OA現金盤平臺出租QQ2952777280【話仙源碼論壇】hxforum.com【木瓜源碼論壇】papayabbs.com一行讀取兩遍的錯覺?
最近在做一個wifiap設置的接口,用戶首先獲取到當前wifi 熱點的ssid 和pwd,然後修改,保存。

獲取信息的時候是fopen對應的hostapd.conf文件,逐行讀取,查找匹配的參數。

修改的時候則是逐行讀取當前hostapd.conf文件,逐行寫到新的臨時配置文件裏面,如果匹配到ssid或者pwd則修改成新的值再寫到新文件裏面。

最後將新的臨時配置文件rename成hostapd.conf。

測試的時修改完後,cat出hostapd.conf的檢查發現最後一行總是重復兩遍。

雖然不影響整體功能,但是非常出乎意料,超出預期設計的效果。

讀取更新的代碼邏輯大致如下

復制代碼
while (!feof(srcF))
{
//get line data
fgets(tmp, sizeof(tmp), srcF);
f = tmp;
LOGD("get %s",f);

                                            //clear space in the head
                                            while(‘ ‘ == *f || ‘\n‘ == *f || ‘\r‘ == *f)
                                                    f++;
                                            if(‘\0‘ == *f)
                                                    continue;
                                            //if the comments copy directly
                                            if(‘#‘ == *f)
                                            {
                                                    LOGD("get comments %s", f);
                                                    fputs(f, dstF);
                                                    continue;
                                            }
                                            p = strstr(f, WIFI_SSID);
                                            //we must makesure it is start with my str
                                            if(p == f)
                                            {
                                                    //replace new ssid name
                                                    p += strlen(WIFI_SSID);
                                                    sprintf(p,"%s\n", ssid);
                                                    LOGD("replace new ssid %s",f);
                                                    fputs(f, dstF);
                                                    continue;
                                            }

                                            p = strstr(f, WIFI_PW);
                                            //we must makesure it is start with my str
                                            if(p == f)
                                            {
                                                    //replace new password
                                                    p += strlen(WIFI_PW);
                                                    sprintf(p,"%s\n",  pw);
                                                    LOGD("replace new pwd%s",f);
                                                    fputs(f, dstF);
                                                    continue;
                                            }
                                            else
                                                    fputs(f, dstF);
                                            LOGD("copy      %s",f);

復制代碼
大概看一下總體的循環邏輯是沒錯

【判斷是否到了文件結束-->讀取一行內容-->將讀取的內容寫到新的文件中】

但是仔細查條件檢查和返回值的判斷,還是發現忽略了一些細節。

1、讀完了最後一行還沒讀到EOF,需要下一次讀取才到EOF。

2、沒有對fgets返回值進行判斷,最後一次讀完再去讀取的時候會返回NULL。

3、沒有對讀取數據的tmp buf進行清空處理。

事實上最後一次沒讀到東西,只是tmp裏面的數據是上一次讀取沒有清空的,所以造成了重復讀取的錯覺。

解決方法如下:

1、判斷fgets返回值,如果是NULL則continue返回去繼續判斷eof

復制代碼
while (!feof(srcF))

{
//get line data
if(NULL == fgets(tmp, sizeof(tmp), srcF))
continue;
...........
}
復制代碼
2、先讀取後判斷eof

復制代碼
while (1)
{
//get line data
fgets(tmp, sizeof(tmp), srcF);
if(feof(srcF))
break;
................

}
復制代碼
以上經過驗證ok。

另外最好在每次使用buf前都進行一次memset,清空緩存。

有關fgetc配合feof逐行讀取文件最後OA現金盤平臺出租一行讀取兩遍的錯覺