日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC中的文件读写技术

發(fā)布時間:2023/12/9 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC中的文件读写技术 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

面向存儲的文件技術

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

為什么要在程序中使用文件?

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

文件類型

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

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

二進制文件:

指對包含任意格式或無格式數(shù)據的文件的統(tǒng)稱。

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

第一部分:文本文件

文本文件的讀寫

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

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

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

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

只要啟動客戶操作記錄軟件后,不管輸入焦點是否在本軟件上,按鍵都會被記錄下來。我們需要的是鍵盤的系統(tǒng)監(jiān)控,只要本軟件在運行,無論當前計算機在做什么,都能監(jiān)測到用戶按鍵的行為并做出反應,這就要用到Hook技術。

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

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

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

如果Hook過程在應用程序中實現(xiàn),若應用程序不是當前窗口時,該Hook就補齊作用;如果Hook在DLL中實現(xiàn),程序在運行中動態(tài)調用它,它能實時對系統(tǒng)進行監(jiān)控。根據需要,我們采用的是在DLL中實現(xiàn)Hook的方式。

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

文本文件存儲管理

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

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

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

為解決漢字的存儲和顯示問題,我國制定了國際GB2312。據此規(guī)定,一個漢字由2個擴展的ASCII碼組成,這種高位為1的雙字節(jié)漢字編碼就是漢字的機內碼,簡稱為內碼。例如,漢字“學”的機內碼用二進制數(shù)表示就是11010001 10100111(即十進制數(shù)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的構造函數(shù)來打開磁盤文件,同時可以用標志位指定打開方式(只讀、只寫、讀寫等):

CStdioFile(LPCTSTR lpszFileName,UINT nOpenFlags);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

步驟:

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

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提供了函數(shù)WriteString來向文本文件中寫入文本,WriteString函數(shù)的格式如下:

void WriteString(LPCTSTR lpsz);

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

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

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

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

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

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提供了函數(shù)ReadString來讀取文本,ReadString有兩種形式,一種為:

virtual LPTSTR ReadString(LPTSTR lpsz, UINIT nMax);

ReadString函數(shù)的參數(shù)如下:

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

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

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

ReadString的另一種形式為:

BOOL ReadString(CString& rString);

參數(shù)rString用來容納從文件讀出的文本。

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

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

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

步驟:創(chuàng)建基于對話框的MFC程序,刪除所有自動添加的控件,添加按鈕控件,為按鈕添加事件,并在相應的函數(shù)處,添加如下代碼:

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單步執(zhí)行,結果如下:

5.關閉文件

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

函數(shù)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();

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

舉例而言,上一段程序本意是想從windows的安裝目錄下面的MyTextFile.txt文件中讀取一行數(shù)據,但是如果操作系統(tǒng)安裝的路徑不是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.超越文件權限進行讀寫操作

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

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

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);

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

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.讀文本文件指定的一行,并得到文本文件的總行數(shù)。

讀文本文件指定的一行,并得到文本文件的總行數(shù)

要統(tǒng)計文本文件的總行數(shù),可以從頭逐行讀,直到文件尾,程序:

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技術完成鍵盤監(jiān)控和寫入文件的功能;另一部分是界面部分,調用DLL啟動和停止客戶操作記錄功能。

第1步:創(chuàng)建MFC DLL項目

第2步:創(chuàng)建TestHook.h文件

第3步:加入全局共享數(shù)據變量

第4步:保存DLL實例句柄

第5步:類CKeyboradHook的成員函數(shù)

第6步:創(chuàng)建鉤子可執(zhí)行程序

第1步:創(chuàng)建MFC DLL項目

創(chuàng)建一個名為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按鈕繼續(xù)下一步,在彈出的對話框中設置DLL類型為MFC Extension DLL(using shared MFC DLL).

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

第2步:創(chuàng)建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()函數(shù)實現(xiàn)安裝鉤子

BOOL StopHook();//StopHook()函數(shù)實現(xiàn)卸載鉤子

};

第3步:加入全局共享數(shù)據變量

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函數(shù)中添加如下代碼:

if (dwReason == DLL_PROCESS_ATTACH)

{

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

//擴展DLL僅初始化一次

if (!AfxInitExtensionModule(HookTestDLL, hInstance))

return 0;

//DLL加入動態(tài)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的成員函數(shù)

//KeyboradProc函數(shù)

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函數(shù)把鉤子信息傳遞給鉤子鏈的下一個鉤子函數(shù)

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

}

第6步:創(chuàng)建鉤子可執(zhí)行程序

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

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:鉤子類型,它是和鉤子函數(shù)類型一一對應的,例如,WH_KEYBOARD表示安裝的是鍵盤鉤子,WH_MOUSE表示的是鼠標鉤子等。

lpfn:鉤子函數(shù)的地址

hMod:鉤子函數(shù)所在的實例的句柄,對于線程鉤子,該參數(shù)為NULL;對于系統(tǒng)鉤子,該參數(shù)為鉤子函數(shù)的DLL句柄

dwThreadId:指定鉤子所監(jiān)視的線程的線程號,對于全局鉤子,該參數(shù)為NULL.

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

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

*/

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

//卸載鉤子

BOOL CHookTest::StopHook()

{

BOOL bResult=FALSE;

if(glhTestHook)

{

bResult=UnhookWindowsHookEx(glhTestHook);

if(bResult)

{

glhTestHook=NULL;

}

}

return bResult;

}

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

第二部分:INI文件

INI文件的讀寫

Windows操作系統(tǒng)將win.ini作為記錄當前系統(tǒng)狀態(tài),并根據其記錄內容對系統(tǒng)進行配置的一種便捷的方法,且眾多的應用軟件也廣泛的使用該類型的配置文件來對軟件進行記錄和配置。

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

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

掌握內容 :

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

INI文件存儲管理

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

;注釋

[小節(jié)名]

關鍵字=值

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

注釋以分號“;”開頭。

Windows操作系統(tǒng)專門為此提供了6個API函數(shù)來對配置設置文件進行讀、寫:

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

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

GetProfileInt:從win.ini獲取整數(shù)值。

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

WriteProfileString:寫字符串到win.ini。

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

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

INI文件讀寫過程

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

1. INI文件的寫過程

將信息寫入INI文件中所用的函數(shù)為:

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

其中各參數(shù)的意義:

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

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

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

lpFileName:是完整的INI文件名。

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

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

步驟:創(chuàng)建基于對話框的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盤下創(chuàng)建了student.ini文件,文件內容如下:

[Info]

Name=張三

Age=12

2. INI文件的讀過程

將信息從 INI文件中讀出到程序中所用的函數(shù)為 :

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

其中,各參數(shù)的意義如下:

前兩個參數(shù)與WritePrivateProfileString中的意義一樣。

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

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

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

nSize:目的緩存器的大小。

lpFileName:是完整的INI文件名。

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

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

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

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文件的路徑必須完整,文件名前面的各級目錄必須存在,否則寫入不成功,該函數(shù)返回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.認識上的兩個誤區(qū)

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

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

解決辦法是lpFileName參數(shù)設置為“.//student.ini”。

教你一招----如何循環(huán)讀寫多個值

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

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”);

//將文件總數(shù)寫入,以便讀出。

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

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

步驟:創(chuàng)建基于對話框的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盤下創(chuàng)建了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按鈕響應事件函數(shù)處,添加如下代碼:

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的內容。

總結

以上是生活随笔為你收集整理的MFC中的文件读写技术的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。