讓你提前認識軟體開發(12):配置檔案讀取及檔案操作
第1部分 重新認識C語言
配置檔案讀取及檔案操作
【文章摘要】
在通訊領域的軟體開發專案中,C語言是主流的程式語言,而檔案操作在其中又佔有很重要的地位。此外,為了體現產品的靈活性,可新增配置檔案對某些重要的引數進行按需配置。這就要求程式能夠準確讀取到各個配置項的值。
本文以一個實際的小軟體為例,介紹了C語言中配置檔案的讀取方法和重要的檔案操作函式的使用方法,為相關軟體開發專案提供了有益的參考。
【關鍵詞】
C語言檔案函式配置檔案操作
1.前言
在一般的軟體專案中,常常需要用C語言對檔案進行操作。在諸如對賬之類的程式中,尤其如此。而C語言中有關檔案操作的函式多達數十種,熟悉常用函式(
靈活性是優秀軟體吸引使用者的特性之一,為了體現軟體的靈活性,可以將相關引數放置到一個配置檔案中,使用者可以根據需要進行設定。因此,C語言中的配置檔案讀取函式也值得關注。
本文以作者編寫過的軟體為例,對C語言中配置檔案的讀取和常用的檔案操作函式的使用方法進行了詳細的介紹。
2.本文使用的軟體、檔案操作函式和配置檔案介紹
2.1本文使用的軟體
本文使用的軟體基於MFC實現,有一個使用者操作的介面,如圖1所示。
圖1軟體操作介面
在本軟體中,三個主要按鈕實現的功能為:
(1)“新增到輸出框”按鈕:從配置檔案中讀取相關資訊,並輸出到上面的空白框中(空白框的屬性為LIST BOX)。
(2)“儲存到檔案”按鈕:將從配置檔案中讀取到的資訊儲存到指定命名格式的檔案中。
(3)“上傳到FTP”按鈕:將(2)中生成的檔案上傳到指定的FTP目錄中。
2.2本文中使用的檔案操作函式
本文使用的檔案操作函式包括fopen、fwrite、fflush、fclose等,對它們的詳細說明如下:
(1) fopen函式
作用:開啟檔案
表頭檔案:#include <stdio.h>
定義函式:FILE *fopen(const char *path, const char *mode);
函式說明:引數path字串包含欲開啟的檔案路徑及檔名,引數mode字串則代表著流形態。
mode有下列幾種形態字串:
r:開啟只讀檔案,該檔案必須存在。
r+:開啟可讀寫的檔案,該檔案必須存在。
w:開啟只寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案。
w+:開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。
a:以附加的方式開啟只寫檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾,即檔案原先的內容會被保留。
a+:以附加方式開啟可讀寫的檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾後,即檔案原先的內容會被保留。
上述的形態字串都可以再加一個b字元,如rb、w+b或ab+等組合,加入b字元用來告訴函式庫開啟的檔案為二進位制檔案,而非純文字檔案。不過在POSIX系統,包含Linux都會忽略該字元。由fopen()所建立的新檔案會具有 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)許可權,此檔案許可權也會參考umask值。
返回值:檔案順利開啟後,指向該流的檔案指標就會被返回。如果檔案開啟失敗,則返回NULL,並把錯誤程式碼存在errno中。
附加說明:一般而言,開啟檔案後會作一些檔案讀取或寫入的動作,若開啟檔案失敗,接下來的讀寫動作也無法順利進行,所以在fopen()後請作錯誤判斷及處理。
(2) fwrite函式
作用:將資料寫至檔案流
表頭檔案:#include <stdio.h>
定義函式:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
函式說明:fwrite()用來將資料寫入檔案流中。引數stream為已開啟的檔案指標,引數ptr指向欲寫入的資料地址,總共寫入的字元數以引數size*nmemb來決定。fwrite()會返回實際寫入的nmemb數目。
返回值:返回實際寫入的nmemb數目。
(3) fflush函式
作用:更新緩衝區
表頭檔案:#include <stdio.h>
定義函式:int fflush(FILE *stream);
函式說明:fflush()會強迫將緩衝區內的資料寫回引數stream指定的檔案中。如果引數stream為NULL,fflush()會將所有開啟的檔案資料更新。
返回值:成功返回0,失敗返回EOF,錯誤程式碼存於errno中。
錯誤程式碼:EBADF引數stream指定的檔案未被開啟,或開啟狀態為只讀。
(4) fclose函式
作用:關閉檔案
表頭檔案:#include <stdio.h>
定義函式:int fclose(FILE *stream);
函式說明:fclose()用來關閉先前fopen()開啟的檔案。此動作會讓緩衝區內的資料寫入檔案中,並釋放系統所提供的檔案資源。
返回值:若關閉檔案動作成功則返回0,有錯誤發生時則返回EOF並把錯誤程式碼存到errno中。
錯誤程式碼:EBADF表示引數stream非已開啟的檔案。
2.3本文中使用的配置檔案
為了程式的正常執行,一般都會事先約定配置檔案的命名及格式。在本文中,配置檔案為Config.ini(ini為配置檔案的常用字尾),檔案中涉及到的配置項及註釋如下:
;用於配置檔案的本地存放路徑
[General]
;檔案的本地存放路徑
LocalPath = D:\
;檔案字首
FilePrefix = EmployeeInfo
;檔案字尾(形如txt,注意,不要加.)
FileSuffix = txt
;新增資訊條數和具體資訊(姓名+工號)
[EmployeeInfo]
;訊息條數
MsgCount = 3
;訊息內容
content1 = 00000001張三
content2 = 00000002李四
content3 = 00000003王五
; FTP資訊,需按照實際情況來配置
[FTP]
; IP地址
IPAddr =
;使用者名稱
UserName =
;密碼
Password =
;傳輸方式:2 - BIN,1 - ASC
Mode = 1
;遠端路徑: FTP上傳時存放檔案的路徑
FTPPath =
在配置檔案中,將相關聯的項放置在同一個大項中,用[]括起來(如上面的紅色字型所示),各個小項的值直接放到等號的後面,註釋部分用分號開頭。
2.4本文中使用的讀取配置操作函式
本文中使用的讀取配置操作函式為GetPrivateProfileInt和GetPrivateProfileString,對它們的詳細說明如下:
(1) GetPrivateProfileInt函式
作用:從配置檔案中讀取一個值,並將結果轉換為整型資料後儲存到變數中。
原型:UINT GetPrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName);
各引數的意義:
1) lpAppName:配置檔案中的大項,用[]括起來的部分(如2.3節的紅色字型所示)。
2) lpKeyName:各大項下小項的欄位名稱,如2.3節中General下的LocalPath。
3) nDefault:如果配置檔案中沒有這個配置項,那麼程式碼中取的預設值。
4) lpFileName:配置檔名,如本文中的Config.ini。
舉例:如本程式要獲取MsgCount的值,則程式碼如下:
int iMsgCount = 0;
iMsgCount = GetPrivateProfileInt("EmployeeInfo", "MsgCount", 0, “Config.ini”);
(2) GetPrivateProfileString函式
作用:從配置檔案中讀取一個值,並將結果轉換為字串型資料後儲存到變數中。
原型:DWORD GetPrivateProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName);
各引數的意義:
1) lpAppName:配置檔案中的大項,用[]括起來的部分(如2.3節的紅色字型所示)。
2) lpKeyName:各大項下小項的欄位名稱,如2.3節中General下的LocalPath。
3) lpDefault:如果配置檔案中沒有這個配置項,那麼程式碼中取的預設值。
4) lpReturnedString:程式碼中存放讀取值的字元陣列。
5) nSize:一般為lpReturnedString字元陣列的大小。
6) lpFileName:配置檔名,如本文中的Config.ini。
舉例:如本程式要獲取FilePrefix的值,則程式碼如下:
char szFilePrefix[100] = {0};
GetPrivateProfileString("General", "FilePrefix", "EmployeeInfo", szFilePrefix, 100, strINIFILE);
2.5本文中使用的FTP操作函式
本文中使用的FTP操作函式為GetFtpConnection和PutFile,對它們的詳細說明如下:
(1) GetFtpConnection函式
作用:連線FTP伺服器。
原型:CFtpConnection* GetFtpConnection(LPCTSTR pstrServer, LPCTSTR pstrUserName, LPCTSTR pstrPassword, INTERNET_PORT nPort, BOOL bPassive);
各引數的意義:
1) pstrServer:服務名,即FTP伺服器的IP地址。
2) pstrUserName:使用者名稱,即登入FTP伺服器的使用者名稱。
3) pstrPassword:密碼,即登入FTP伺服器的密碼。
4) nPort:埠號,該引數預設值為INTERNET_INVALID_PORT_NUMBER。
5) bPassive:該項的預設值為FALSE。
(2) PutFile函式
作用:FTP上傳檔案。
原型:BOOL PutFile(LPCTSTR pstrLocalFile, LPCTSTR pstrRemoteFile, DWORD dwFlags, DWORD_PTR dwContext);
各引數的意義:
1) pstrLocalFile:帶存放路徑的本地檔名。
2) pstrRemoteFile:帶存放路徑的遠端檔名,即檔案存放在FTP伺服器的何處。
3) dwFlags:標識,該項取預設值FTP_TRANSFER_TYPE_BINARY。
4) dwContext:上下文標識,該項取預設值1。
3.程式流程
如2.1節所述,本程式主要實現三個功能,對應的配置檔案如2.3節所示。每個功能的流程及相關說明如下:
3.1將配置檔案中的資料新增到輸出框
(1)該功能的流程圖
如圖2所示:
圖2將配置檔案中的資料新增到輸出框流程圖
(2)訊息內容格式及異常考慮
本程式採用的訊息內容格式為:工號姓名,如“00000001張三”,“00000001”表示工號,“張三”為姓名。在輸出框裡面,也是這樣顯示的。如圖3所示。
圖3 單擊“新增到輸出框”後的輸出內容
本流程的異常情況主要考慮以下方面:
1) MsgCount項的值為空或0。
2)訊息內容項(即content1、content2、content3等)為空或出現內容完全相同。
3)訊息內容格式不正確,即不是“工號姓名”的格式。
4)工號相同(一般而言,員工工號不能相同)。
3.2將配置檔案中的資料寫入檔案
(1)該功能的流程圖
如圖4所示:
圖4將配置檔案中的資料寫入檔案流程圖
(2)檔案命名、檔案訊息內容格式及異常考慮
檔案命名格式為:FilePrefix時分秒.FileSuffix,如“EmployeeInfo155431.txt”。
檔案訊息內容格式與輸出框格式一樣,即“工號姓名”。如圖5所示。
圖5 單擊“儲存到檔案”後的輸出檔案內容
本流程考慮的異常情況與3.1節相同。
(3)有關檔案操作函式的使用說明
1)對於fopen函式,由於要向檔案中寫入資料,因此“mode”引數可以採用“a”等,但不能採用“r”等表示只能讀取的引數。
2)使用fwrite函式將資料寫入檔案,注意要在每條資料的最後面加上“\n”表示回車換行。
3)在寫入資料完成之後,一定要加上fclose函式關閉檔案,並且fclose函式一定要與fopen函式配對,且在使用fclose函式之後,要將檔案指標置為null。
3.3將生成的檔案上傳到FTP伺服器
(1)該功能的流程圖
如圖6所示:
圖6將生成的檔案上傳到FTP伺服器流程圖
(2)有關FTP操作的說明
1)在執行操作之前,一定要確保FTP伺服器的各項引數都配置正確。對於“Mode”項,1表示以ASC方式上傳,2表示以二進位制方式上傳。
2) FTP操作的最大重試次數可根據需要進行設定,一般為3次。
4.對本軟體進行測試
在程式執行起來之後,接下來的工作就是對之進行大量的測試,一定要對本程式涉及到的三個主要功能均進行充分的測試。
為了使得測試順利進行,在執行本軟體之前,需要將本軟體和配置檔案放在同一個資料夾的同一級目錄下。當然,也可以在程式碼中設定特殊的配置檔案存放目錄。
對於“將配置檔案中的資料新增到輸出框”功能,檢查輸出框上面顯示的內容是否和配置檔案裡面的資訊一致,並對幾種異常情況進行大量的測試。
對於“將配置檔案中的資料寫入檔案”功能,檢查檔案命名是否符合要求、檔案存放地址是否正確、檔案裡面的內容是否和輸出框顯示的資訊一致,同時要對幾種異常情況進行大量的測試。
對於“將生成的檔案上傳到FTP伺服器”功能,檢查FTP伺服器上對應目錄是否有檔案存在,並對異常情況(如FTP資訊配置不準確、本地檔案不存在、遠端路徑不存在等)進行一定的測試。
5.總結
檔案操作和配置檔案在實際的軟體開發專案中是很常見的,掌握C語言中常用檔案操作函式的使用方法是對一個軟體開發工程師的基本要求。
本文用例項來描述了C語言中常用的檔案操作函式的用法及配置檔案的使用方法。“冰凍三尺,非一日之寒”,要想熟練掌握C語言中常用檔案操作函式及配置檔案的用法,還需要我們不斷地練習和總結。