MFC文件讀寫

計算機室如何管理自身所存放着的大量的信息的呢?windows的磁盤管理程序爲我們提供了一套嚴密而又高效的信息組織形式--硬盤上的信息是以文件的形式被管理的。

面向存儲的文件技術

什麼是文件?計算機中,一篇文章、一幅圖片、一個程序等都是以文件的形式存儲在磁盤上的,每個文件都有一個文件名。計算機就是對文件按名存取的。文件名的格式如下:主文件名.擴展名。

爲什麼要在程序中使用文件?

通常,程序中的數據在程序運行結束之後,就會從內存中清除,再次運行程序時不會自動出現。在編制程序的過程中不可避免的會遇到將某些數據永久保存的問題,當程序關閉後,依然可以使用這些數據,這時就需要進行文件操作。

文件類型

Visual C++處理的文件通常分爲兩種:

文本文件:只可被任意文本編輯器讀取ASCII文本。

二進制文件:

指對包含任意格式或無格式數據的文件的統稱。

這裏只介紹文本文件的讀寫,INI文件也屬於文本文件的範疇,且INI文件的結構和用途與普通的文本文件不同,所以會單獨介紹。

第一部分:文本文件

文本文件的讀寫

認識CFile類;認識文本文件;能夠正確靈活應用文本文件存取信息;避免文本文件讀寫的常見誤區。

CFile是MFC的文件操作基本類,它直接支持無緩衝的二進制磁盤I/O操作,並通過其派生類支持文本文件、內存文件和socket文件。

客戶操作記錄實例功能預覽及關鍵知識點

許多系統,出於安全或其他原因,常常要求隨時對鍵盤進行監控,利用Hook(鉤子)技術編寫的應用程序能夠很好地達到這個目的。本軟件就製作了一個客戶操作記錄軟件,即在軟件運行過程中,用戶在鍵盤上的按鍵操作會被記錄下來,這樣對維護軟件的正常運行非常有利。

只要啓動客戶操作記錄軟件後,不管輸入焦點是否在本軟件上,按鍵都會被記錄下來。我們需要的是鍵盤的系統監控,只要本軟件在運行,無論當前計算機在做什麼,都能監測到用戶按鍵的行爲並做出反應,這就要用到Hook技術。

Hook技術在很多特殊軟件中廣泛應用,如,金山詞霸的“取詞”功能,就用到了Hook計技術。

鉤子的本質是一段用以處理系統消息的程序,通過系統調用,將其掛入系統。鉤子的種類很多,每種鉤子可以截獲並處理相應的消息,每當特定的消息發出,在到達目的窗口之前,鉤子程序先行截獲該消息、得到對此消息的控制權。此時在鉤子函數中就可以對截獲的消息進行加工處理,甚至可以強制結束消息的傳遞。

從鉤子的本質來看,可以優先截獲操作系統的各種消息進行處理,所以它幾乎無所不能,因爲windows的應用程序都是基於消息驅動的,應用程序的操作都依賴於它所得到的消息的類型及內容。

如果Hook過程在應用程序中實現,若應用程序不是當前窗口時,該Hook就補齊作用;如果Hook在DLL中實現,程序在運行中動態調用它,它能實時對系統進行監控。根據需要,我們採用的是在DLL中實現Hook的方式。

(應用程序exe? 和DLL的區別所在)

文本文件存儲管理

字符被計算機處理時都是以二進制代碼的形式出現的,即一個字符對應一個8位二進制數,這種二進制碼的集合就是所謂的ASCII碼。

基本的ASCII碼有128個,最高位都是0,對應的十進制數是0-127。鍵盤上的字符,如英文字母、數字和一些常用符號,使用基本ASCII部分。如數字“0”的ASCII碼用二進制數表示就是00110000(即十進制數48)。

擴展的ASCII碼有128個,最高位是1,對應的十進制數是128-255。一些製表符和其他符號使用擴展的ASCII碼部分。

爲解決漢字的存儲和顯示問題,我國制定了國際GB2312。據此規定,一個漢字由2個擴展的ASCII碼組成,這種高位爲1的雙字節漢字編碼就是漢字的機內碼,簡稱爲內碼。例如,漢字“學”的機內碼用二進制數表示就是11010001 10100111(即十進制數206 和167 ),用十進制表示就是53671(206*256+167)。對於字符,文本文件存儲的是它的ASCII碼,對於漢字,文本文件存儲的是它的內碼,即兩位ASCII碼,如字符串“0學0”,在文本文件中存儲的內容是00110000 11010001 10100111 00110000

正確的文本文件讀寫過程

1.定義文件變量;2.打開指定的文件;3.向從文本文件中寫入信息;4.從文本文件中讀取信息;5.關閉文件

1、定義文件變量

定義文件變量格式:CStdioFile 文件變量;

例如,定義一個名稱爲f1的文件變量,語句如下:CStdioFile f1;

 

2、打開指定文件

可以直接通過CStdioFile的構造函數來打開磁盤文件,同時可以用標誌位指定打開方式(只讀、只寫、讀寫等):

CStdioFile(LPCTSTR lpszFileName,UINT nOpenFlags);

其中,lpszFileName表示要打開的文件名,可以是相對路徑或絕對路徑

nOpenFlags設置文件打開方式標誌位,可以指定用“|”連接多個標誌位。下面是常用的打開標誌:

CFile::typeText:以文本文件的形式打開文件

CFile::typeBinary:以二進制文件的形式打開文件

CFile::modeCreate:如果指定文件名的文件不存在,則新建文件;如果文件存在並且沒有設置CFile::modeNoTruncate標誌,則清空文件。

CFile::modeNoTruncate:如果文件存在,不把它的長度刪除爲0(即不清空文件中的數據)。

CFile::modeRead:以只讀方式打開文件

CFile::modeReadWrite:以可讀可寫方式打開文件

CFile::modeWrite:以只寫方式打開文件

CFile::shareDenyNone:文件打開後,不禁止其他進程對文件的讀寫操作

CFile::shareExclusive:文件打開後,禁止其他進程對文件的讀寫操作

CFile::shareDenyRead:文件打開後,禁止其他進程對文件的讀操作

CFile::shareDenyWrite:文件打開後,禁止其他進程對文件的寫操作

此外,可以不在構造函數中打開文件,而僅僅調用空的構造函數CStidoFile(),然後用CStdioFile::Open()打開文件。Open函數的前兩個參數和非空構造函數的參數相同,其聲明如下:

BOOL Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError=NULL);

第3個參數與打開失敗時的異常處理有關。

實例1:以只讀方式打開一個文件

步驟:

使用AppWizard創建一個對話框應用程序,刪除其自動產生的所有控件,添加一個Button控件。雙擊控件,在相應的函數裏添加代碼:

char * pszFileName="C://myfile.txt";

CStdioFile myFile;

CFileException fileException;

if(!myFile.Open(pszFileName,CFile::modeCreate|CFile::typeText|CFile::modeRead),&fileException)

{

TRACE("Can't open file %s, error = %u/n",pszFileName,fileException.m_cause);

}

運行結果:如果C:/下沒有myfile.txt文件,則新生成該文件。

3.向從文本文件中寫入信息

CStdioFile提供了函數WriteString來向文本文件中寫入文本,WriteString函數的格式如下:

void WriteString(LPCTSTR lpsz);

WriteString的參數lpsz是一個以”/0”字符結束的字符串,要把這個字符串的內容寫入文件。

提示:使用WriteString函數時,如果希望每執行一次WriteString,文本文件中的內容就會自動換行一次,那麼就需要在需要換行的地方輸出“/n”:

myFile.WriteString(“第1行/n”);

實例2:向文件中寫入文本

建立MFC基於對話框的程序,刪除自動添加的所有控件,添加一個“確定”按鈕,雙擊按鈕,按默認添加事件函數,雙擊按鈕,在相應的函數處添加如下代碼:

char* pszFileName="C://myfile.txt";

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(pszFileName,CFile::typeText|CFile::modeCreate|CFile::modeReadWrite),&fileException)

{

myFile.WriteString("第1行/n");

CString strOrder;

strOrder.Format("%d,%.3f",66,88.88);

myFile.WriteString(strOrder);

}

else

{

TRACE("Can't open file %s,error=%u/n",pszFileName,fileException.m_cause);

}

程序運行結果:C:/myfile.txt文件中內容如下:

第1行

66,88.880

4.從文本文件中讀取信息

CStidoFile提供了函數ReadString來讀取文本,ReadString有兩種形式,一種爲:

virtual LPTSTR ReadString(LPTSTR lpsz, UINIT nMax);

ReadString函數的參數如下:

lpsz :是用戶提供的一個指向字符串的指針,它用來接受從文件讀出的文本,以”/0”結束。

nMax是本次所允許讀入的文本字符個數,不計“/0”字符,也就是說最多能讀入nMax-1個文本字符。

ReadString的返回值是一個LPTSTR類型的指針,它指向從文件讀出的文本字符串,如果到達文件尾,則返回NULL。

ReadString的另一種形式爲:

BOOL ReadString(CString& rString);

參數rString用來容納從文件讀出的文本。

CString版本忽略回車換行符,返回值是一個布爾值。如果返回值爲FALSE,表示因到達文件尾而沒有讀到任何字符。

提示:每執行一次ReadString,就會自動從文本文件中讀取一行數據,同時文件操作指針會自動跳轉到下一行。

實例3:從文件中讀取文本信息

步驟:創建基於對話框的MFC程序,刪除所有自動添加的控件,添加按鈕控件,爲按鈕添加事件,並在相應的函數處,添加如下代碼:

char* pszFileName="C://myfile.txt";

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(pszFileName,CFile::typeText|CFile::modeReadWrite),&fileException)

{

myFile.SeekToBegin();

CString str1;

myFile.ReadString(str1);

CString str2;

myFile.ReadString(str2);

AfxMessageBox(str1+str2);

}

else

{

TRACE("Can't open file %s,error=%u/n",pszFileName,fileException.m_cause);

}

myFile.Close();

程序運行結果:爲程序F9設置斷點,然後F5單步執行,結果如下:

clip_image001

5.關閉文件

對文件的操作完成後,使用CloseFile關閉文件。

函數CStdioFile::Close關閉一個文件,一般一個文件使用完畢就應該關閉它:

myFile.Close();

錯誤的文本文件讀寫過程

在讀寫文本文件的時候,最常見的錯誤是---操作文件不存在。這種錯誤產生的典型原因有:

1.路徑錯誤

char * pszFileName="C://Windows//MyFile.txt";

CStdioFile myFile;

CFileException fileException;

if(!myFile.Open(pszFileName,CFile::modeCreate|CFile::typeText|CFile::modeReadWrite),&fileException)

{

//文件操作代碼

}

else

{

TRACE("Can't open file %s, error = %u/n",pszFileName,fileException.m_cause);

}

myFile.Close();

由於將文件變量與一個絕對路徑的文件名關聯,而程序的數據通常存儲在相對路徑下,所以一旦相對路徑和相對路徑不一致時,就會出錯。

舉例而言,上一段程序本意是想從windows的安裝目錄下面的MyTextFile.txt文件中讀取一行數據,但是如果操作系統安裝的路徑不是C:/Windwos,而是C:/Winnt,那麼這段程序就會出錯。

解決方法是在程序中使用相對路徑,改正後的程序如下:

//獲取windows路徑

LPTSTR lpBuffer=new char[MAX_PATH];

::GetWindowsDirectory(lpBuffer,MAX_PATH);

strcat(lpBuffer,"//MyFile.txt");

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(lpBuffer,CFile::typeText|CFile::modeCreate|CFile::modeReadWrite),&fileException)

{

//文件操作代碼

}

else

{

TRACE("Can't open file %s, error = %u/n",pszFileName,fileException.m_cause);

}

CString strFileTitle="MyFile.txt";

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(strFileTitle,CFile::typeText|CFile::modeReadWrite),&fileException)

{

//文件操作代碼

myFile.WriteString("測試!");

}

else

{

TRACE("Can't open file %s, error = %u/n",pszFileName,fileException.m_cause);

}

myFile.Close();

2.操作文件不存在

如果應用程序所有路徑下面不存在MyFile.txt文件,那麼在WriteString寫入信息時就會出錯。

解決辦法就是在程序中打開文件前要檢查是否存在此文件。如下程序:

CString strFileTitle="MyFile.txt";

CFileFind finder;

if(finder.FindFile(strFileTitle))

{

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(lpBuffer,CFile::typeText|CFile::modeCreate|CFile::modeReadWrite),&fileException)

{

//文件操作代碼

}

else

{

TRACE("Can't open file %s, error = %u/n",pszFileName,fileException.m_cause);

}

}

else

{

TRACE("Can't find file %s/n",strFileTitle);

}

myFile.Close();

3.超越文件權限進行讀寫操作

在打開文件的過程中,通過參數指定了文件的讀寫權限,如果讀寫的操作沒有和相應的權限對應,就會出現錯誤。

下面的程序就是典型的忽略了文件操作權限的例子:

CString strFileTitle="MyFile.txt";

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(strFileTitle,CFile::typeText|CFile::modeCreate|CFile::NoTruncate|CFile::modeRead),&fileException)

{

//文件操作代碼

myFile.WriteString("測試!");

}

else

{

TRACE("Can't open file %s,error=%u/n",strFileTitle,fileException.m_cause);

}

myFile.Close();

支招兒:

1.準確定位文件的路徑

操作文件的過程中,經常需要將文本文件放在程序自身的目錄中,但是如果僅僅在程序中使用不指定任何路徑信息的相對路徑,如:

myFile.Open("MyFile.txt",CFile::modeCreate|CFile::typeText|CFile::modeReadWrite);

那麼就有可能出現不能正確定位的情況,準確定位文件位置的方法是獲得可執行程序自身的絕對路徑,如:

TCHAR FilePath[MAX_PATH];

GetModuleFileName(NULL,FilePath,MAX_PATH);

(_tcstchr(FilePath,'//'))[1]=0;

lstrcat(FilePath,_T("MyFile.txt"));

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(FilePath,CFile::modeCreate|CFile::typeText|CFile::modeReadWrite),&fileException)

{

//文件操作代碼

}

else

{

TRACE("Can't open file %s,error=%u/n",FilePath,fileException.m_cause);

}

myFile.Close();

2.讀文本文件指定的一行,並得到文本文件的總行數。

讀文本文件指定的一行,並得到文本文件的總行數

要統計文本文件的總行數,可以從頭逐行讀,直到文件尾,程序:

CStdioFile myFile;

CFileException fileException;

if(myFile.Open("MyFile.txt",CFile::modeCreate|CFile::modeNoTruncate|CFile::typeText|CFile::modeReadWrite),&fileException)

{

CString strContent;

int order=1;

while(myFile.ReadString(strContent))

{

if(2==order)

{

AfxMessageBox(strContent);

}

order=order+1;

}

}

else

{

TRACE("Can't open file");

}

myFile.Close();

實例演示文件操作過程

客戶操作記錄實例

本軟件分爲兩個部分,一部分是DLL模塊,裏面利用Hook技術完成鍵盤監控和寫入文件的功能;另一部分是界面部分,調用DLL啓動和停止客戶操作記錄功能。

第1步:創建MFC DLL項目

第2步:創建TestHook.h文件

第3步:加入全局共享數據變量

第4步:保存DLL實例句柄

第5步:類CKeyboradHook的成員函數

第6步:創建鉤子可執行程序

第1步:創建MFC DLL項目

創建一個名爲HookTest的project,project的類型爲選擇MFC AppWizard(DLL),DLL類型爲MFC Extension DLL(using shared MFC DLL)

注意:選擇File->New菜單項,在彈出對話框的左邊的列表框中選擇MFC AppWizard(DLL).

在project name文本框中輸入項目名稱,HookTest;location中輸入項目的存盤路徑;選中Create new workspace;在platForms列表中選擇Win32選項。

單擊OK按鈕繼續下一步,在彈出的對話框中設置DLL類型爲MFC Extension DLL(using shared MFC DLL).

在IDE中,選擇FileView選項卡,在其中就會發現其中有HookTest.cpp文件,卻沒有HookTest.h文件,這是因爲visual C++6.0中沒有現成的鉤子類,所以要自己動手創建TestHook.h文件,在其中建立鉤子類。

第2步:創建TestHook.h文件

選擇File菜單,再選擇New菜單項,將彈出New對話框。選擇files選項卡,並且選擇其中的C/C++ Header File.

選中add to project,並且在對應的下拉列表中選擇項目名稱HookTest;在location文本框中輸入項目的存盤路徑,或單擊右邊的按鈕選擇相應的路徑;在file對應的文本框中輸入文件名HookTest.h;單擊OK按鈕,在IDE中自動打開Hooktest.h文件供編輯代碼用;

TestHook.h文件:

#if _MSC_VER>1000

#pragma once

#endif //_MSC_VER>1000

class AFX_EXT_CLASS CHookTest:public CObject

{

public:

CHookTest();

~CHookTest();

BOOL StartHook();//StartHook()函數實現安裝鉤子

BOOL StopHook();//StopHook()函數實現卸載鉤子

};

第3步:加入全局共享數據變量

HookTest.cpp文件中添加:

//存儲各個鍵賭贏的字符

CString cskey[TOTAL_KEYS]=

{

"BACKSPACE",

"TAB",

……

"F12",

};

//存儲各個鍵對應的鍵值

int nkey[TOTAL_KEYS]=

{

0X08, //"BACKSPACE",

0X09, //"TAB",

…….

0x7b,//"F12",

};

#pragma data_seg("mydata")

//安裝的鍵盤鉤子子句柄

HHOOK glhTestHook=NULL;

//DLL實例句柄

HINSTANCE glhkInstance=NULL;

#pragma data_seg()

第4步:保存DLL實例句柄

DllMain函數中添加如下代碼:

if (dwReason == DLL_PROCESS_ATTACH)

{

TRACE0("HOOKTEST.DLL Initializing!/n");

//擴展DLL僅初始化一次

if (!AfxInitExtensionModule(HookTestDLL, hInstance))

return 0;

//DLL加入動態MFC類庫中

new CDynLinkLibrary(HookTestDLL);

//保存DLL實例句柄

glhkInstance=hInstance;

}

else if (dwReason == DLL_PROCESS_DETACH)

{

TRACE0("HOOKTEST.DLL Terminating!/n");

//終止這個鏈接庫前調用它

AfxTermExtensionModule(HookTestDLL);

}

return 1; // ok

第5步:類CKeyboradHook的成員函數

//KeyboradProc函數

LRESULT WINAPI KeyboradProc(int nCode,WPARAM wParam,LPARAM lParam)

{

for(int i=0;i<TOTAL_KEYS;i++)

{

if(nkey[i]==(int)wParam)

{

int nKeyStatus=lParam &0x80000000;

//根據用戶按鍵播放對應的聲音文件

switch(nKeyStatus)

case 0://WM_KEYUP

//case 0x80000000://WM_KEYUP

{

char* pszFileName="C://myfile.txt";

CStdioFile myFile;

CFileException fileException;

if(myFile.Open(pszFileName,CFile::typeText|CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite),&fileException)

{

myFile.SeekToEnd();

//將文件指針移動到文件末尾準備進行追加文本的操作

//此處可以編寫追加文本的操作

myFile.WriteString(cskey[i]);

}

else

{

TRACE("Can't open file %s,error=%u/n",pszFileName,fileException.m_cause);

}

}

}

}

//調用CallNextHookEx函數把鉤子信息傳遞給鉤子鏈的下一個鉤子函數

return CallNextHookEx(glhTestHook,nCode,wParam,lParam);

}

第6步:創建鉤子可執行程序

//****************************

BOOL CHookTest::StartHook()

{

glhTestHook=SetWindowsHookEx(WH_KEYBOARD,KeyboradProc,glhkInstance,0);

if(glhTestHook!=NULL)

return TRUE;

return FALSE;

}

//****************************

/*

HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,INSTANCE hMod,DWORD dwThreadId)

idHook:鉤子類型,它是和鉤子函數類型一一對應的,例如,WH_KEYBOARD表示安裝的是鍵盤鉤子,WH_MOUSE表示的是鼠標鉤子等。

lpfn:鉤子函數的地址

hMod:鉤子函數所在的實例的句柄,對於線程鉤子,該參數爲NULL;對於系統鉤子,該參數爲鉤子函數的DLL句柄

dwThreadId:指定鉤子所監視的線程的線程號,對於全局鉤子,該參數爲NULL.

SetWindowsHookEx返回所安裝的鉤子句柄。

調用StartHook函數後,所有鍵盤的消息都會轉移到KeyboradProc函數中,通過數組nkey的值與wParam參數相比較,可以知道用戶按下的是哪個鍵,通過對IParam值的判斷,可以知道是按下鍵還是釋放鍵,然後播放鍵對應的聲音文件即可。

*/

//****************************

//卸載鉤子

BOOL CHookTest::StopHook()

{

BOOL bResult=FALSE;

if(glhTestHook)

{

bResult=UnhookWindowsHookEx(glhTestHook);

if(bResult)

{

glhTestHook=NULL;

}

}

return bResult;

}

//****************************

第二部分:INI文件

INI文件的讀寫

Windows操作系統將win.ini作爲記錄當前系統狀態,並根據其記錄內容對系統進行配置的一種便捷的方法,且衆多的應用軟件也廣泛的使用該類型的配置文件來對軟件進行記錄和配置。

配置設置文件(INI)文件是windows操作系統中的一種特殊的ASCII文件,以ini爲文件擴展名。該文件也被稱爲初始化文件initialization file和概要文件profile,通常應用程序可以擁有自己的配置設置文件來存儲狀態信息。一般來說私有的配置設置文件比較小,這樣可以減少程序在初始化時讀取配置文件時的信息量,從而提高程序的啓動速度、提高應用程序和系統的性能。

如果帶存取的信息涉及到windows系統環境或是其他應用程序時,就必須在windows系統的配置文件win.ini中記錄並在訪問的同時發送WM_WININICHANGE消息給所有的頂層窗口,通知其他的程序系統配置文件已做了更改。但由於win.ini中不僅記錄了系統的有關信息,也存儲着許多其他應用軟件的配置數據,所以訪問的數據量要遠比私有配置文件大的多。

掌握內容 :

瞭解INI文件的結構;能夠正確靈活的應用INI文件存取信息;避免INI文件讀寫的常見誤區。

INI文件存儲管理

配置文件裏的信息之所以能爲系統和終生的軟件所讀取並識別,是由於其內部對數據的存取採用了預先約定的“項-值對(entry-value pairs)”存儲結構,並對待存取的數據分門別類地進行調理清晰的存儲。INI文件的結構如下:

;註釋

[小節名]

關鍵字=值

INI文件允許有多個小節,每個小節又允許有多個關鍵字,“=”後面是該關鍵字的值。值的類型有3種:字符串、整型數值和布爾值。其中字符串存儲在INI文件中時沒有引號,布爾值用1表示,布爾假值用0表示。

註釋以分號“;”開頭。

Windows操作系統專門爲此提供了6個API函數來對配置設置文件進行讀、寫:

GetPrivateProfileInt: 從私有初始化文件(即自定義的INI文件)獲取整型數值。

GetPrivateProfileString: 從私有初始化文件獲取字符串型值。

GetProfileInt:從win.ini獲取整數值。

WritPrivateProfileString:寫字符串到私有初始化文件。

WriteProfileString:寫字符串到win.ini。

需要指出的是,當向配置文件存儲信息時,不論是數據還是字符串都要先轉換成字符串,然後再進行存儲。

這裏只介紹私有初始化文件,所以只涉及到3個函數---GetPrivateProfileString、GetPrivateProfileInt和WritePrivateProfileString。

INI文件讀寫過程

INI文件的讀和寫操作是分開的,首先介紹寫文件的方法。

1. INI文件的寫過程

將信息寫入INI文件中所用的函數爲:

BOOL WritePrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpString,LPCTSTR lpString,LPCTSTR lpFileName);

其中各參數的意義:

lpAppName:是INI文件中的一個字段名。

lpKeyName:是lpAppName下的一個鍵名,通俗講就是變量名。

lpString:是鍵值,也就是變量的值,不過必須爲LPCTSTR型或CString型的。

lpFileName:是完整的INI文件名。

實例1:將信息寫入INI文件

將一名學生的姓名和年齡寫入C:/student.ini文件中。

步驟:創建基於對話框的MFC程序,刪除所有自動生成的控件,然後添加按鈕控件,並在相應的按鈕事件處添加如下代碼:

CString strName,strTemp;

int nAge;

strName="張三";

nAge=12;

::WritePrivateProfileString("Info","Name",strName,"C://student.ini");

strTemp.Format("%d",nAge);

::WritePrivateProfileString("Info","Age",strTemp,"C://student.ini");

運行結果:C盤下創建了student.ini文件,文件內容如下:

[Info]

Name=張三

Age=12

2. INI文件的讀過程

將信息從 INI文件中讀出到程序中所用的函數爲 :

DWORD GetPrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpDefault,LPTSTR lpReturnedString,DWORD nSize,LPCTSTR lpFileName);

其中,各參數的意義如下:

前兩個參數與WritePrivateProfileString中的意義一樣。

lpDefault:如果INI文件中沒有前兩個參數指定的字段名或鍵名,則將此值賦給變量。

lpReturnedString:接收INI文件中沒有前兩個參數指定的字段名或鍵名,則將此值賦給變量。

lpReturnedString:接受INI文件中的值的CString對象,即目的緩存器。

nSize:目的緩存器的大小。

lpFileName:是完整的INI文件名。

實例2:從INI文件讀出信息

程序將C:/student.ini文件中的信息讀出到程序中。

步驟:如前,在相應的button按鈕響應事件函數處,添加如下代碼:

CString strStudName;

int nStudAge;

GetPrivateProfileString("Info","Name","默認姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"C://student.ini");

//讀入整型值

//UINT GetPrivateProfileInt(LPCTSTR lpAppName,LPCTSTR lpKeyName,INT nDefault,LPCTSTR lpFileName);

nStudAge=GetPrivateProfileInt("Info","Age",10,"C://student.ini");

運行結果:可以通過設置斷點,來查看strStudName和nStudAge的內容。

錯誤的INI文件讀寫

1.路徑指示錯誤

INI文件的路徑必須完整,文件名前面的各級目錄必須存在,否則寫入不成功,該函數返回FALSE值。

如下程序:

CString strName,strTemp;

int nAge;

strName=”張三”;

nAge=12;

::WritePrivateProfileString(“Info”,”Name”,strName,”c://Info/student.ini”);

如果C:/Info目錄不存在,那麼寫INI文件的操作就會失敗。

解決辦法是進行文件操作前通過以下代碼檢查目錄是否存在:

WIN32_FIND_DATA fd;

HANDLE hFind=FindFirstFile(“C://Info”,&fd);

If((hFind!=INVALID_HANDLE_VALUE)&&(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))

{

AfxMessageBox(“存在”);

}

else

{

AfxMessageBox(“不存在”);

}

FindClose(hFind);

2.認識上的兩個誤區

誤區一:寫文件路徑的時候寫成諸如C:/Info的形式,實際上在visual C++中,文件名的路徑中必須爲//,因爲在visual C++中//才表示一個/,所以正確的格式應改爲C://Info.

誤區二:因爲經常需要把INI文件放在程序所在目錄,所以在寫INI文件的函數中直接將lpFileName參數設置爲文件名,如“student.ini”。這是不正確的做法,打開INI文件的時候,如果文件名沒有指明路徑的話,那麼這個INI文件會存儲在windows目錄中,而不是在應用程序的當前目錄中。

解決辦法是lpFileName參數設置爲“.//student.ini”。

教你一招----如何循環讀寫多個值

假設現在有一個程序,要將最近使用的幾個文件名保存下來,寫入的代碼如下:

CString strTemp,strTempA;

int I;

int nCount=6;

for(i=0;i<nCount;i++)

{

strTemp.Format(“%d”,i);

strTemp.Format(“%s%d%s”,”File”,i,”.txt”);//文件名

::WritePrivateProfileStirng(“UseFileName”,”FileName”+strTemp,strTempA,”c://usefile.ini”);

}

strTemp.Format(“%d”,nCount);

::WritePrivateProfileString(“FileCount”,”Count”,strTemp,”C://usefile.ini”);

//將文件總數寫入,以便讀出。

以上代碼運行後,C盤下面userfile.ini文件內容。

實例3:將信息寫入INI文件

步驟:創建基於對話框的MFC程序,刪除所有自動生成的控件,然後添加按鈕控件,並在相應的按鈕事件處添加如下代碼:

CString strTemp,strTempA;

int i;

int nCount=6;

for(i=0;i<nCount;i++)

{

strTemp.Format("%d",i);

strTempA.Format("%s%d%s","File",i,".txt");//文件名

::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,"c://usefile.ini");

}

strTemp.Format("%d",nCount);

::WritePrivateProfileString("FileCount","Count",strTemp,"C://usefile.ini");

運行結果:C盤下創建了usefile.ini文件,文件內容如下:

[UseFileName]

FileName0=File0.txt

FileName1=File1.txt

FileName2=File2.txt

FileName3=File3.txt

FileName4=File4.txt

FileName5=File5.txt

[FileCount]

Count=6

實例4:從INI文件讀出信息

程序將C:/student.ini文件中的信息讀出到程序中。

步驟:如前,在相應的button按鈕響應事件函數處,添加如下代碼:

CString strTemp,strTempA;

int i;

int nCount;

nCount=::GetPrivateProfileInt("FileCount","Count",0,"c://usefile.ini");

for(i=0;i<nCount;i++)

{

strTemp.Format("%d",i);

strTemp="FileName"+strTemp;

::GetPrivateProfileString("UseFileName",strTemp,"default.txt",strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c://usefile.ini");

//strTempA中就存儲了文件名

}

運行結果:可以通過設置斷點,來查看strTemp和strTempA的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章