計算機室如何管理自身所存放著的大量的信息的呢,?windows的磁盤管理程序為我們提供了一套嚴密而又高效的信息組織形式--硬盤上的信息是以文件的形式被管理的,。 面向存儲的文件技術(shù) 什么是文件?計算機中,,一篇文章,、一幅圖片、一個程序等都是以文件的形式存儲在磁盤上的,,每個文件都有一個文件名,。計算機就是對文件按名存取的。文件名的格式如下:主文件名.擴展名,。 為什么要在程序中使用文件,? 通常,程序中的數(shù)據(jù)在程序運行結(jié)束之后,,就會從內(nèi)存中清除,,再次運行程序時不會自動出現(xiàn),。在編制程序的過程中不可避免的會遇到將某些數(shù)據(jù)永久保存的問題,,當程序關(guān)閉后,依然可以使用這些數(shù)據(jù),,這時就需要進行文件操作,。 文件類型 Visual C++處理的文件通常分為兩種: 文本文件:只可被任意文本編輯器讀取ASCII文本。 二進制文件: 指對包含任意格式或無格式數(shù)據(jù)的文件的統(tǒng)稱,。 這里只介紹文本文件的讀寫,,INI文件也屬于文本文件的范疇,且INI文件的結(jié)構(gòu)和用途與普通的文本文件不同,,所以會單獨介紹,。 第一部分:文本文件 文本文件的讀寫 認識CFile類;認識文本文件,;能夠正確靈活應(yīng)用文本文件存取信息,;避免文本文件讀寫的常見誤區(qū)。 CFile是MFC的文件操作基本類,,它直接支持無緩沖的二進制磁盤I/O操作,,并通過其派生類支持文本文件、內(nèi)存文件和socket文件,。 客戶操作記錄實例功能預(yù)覽及關(guān)鍵知識點 許多系統(tǒng),,出于安全或其他原因,常常要求隨時對鍵盤進行監(jiān)控,,利用Hook(鉤子)技術(shù)編寫的應(yīng)用程序能夠很好地達到這個目的,。本軟件就制作了一個客戶操作記錄軟件,即在軟件運行過程中,用戶在鍵盤上的按鍵操作會被記錄下來,,這樣對維護軟件的正常運行非常有利,。 只要啟動客戶操作記錄軟件后,不管輸入焦點是否在本軟件上,,按鍵都會被記錄下來,。我們需要的是鍵盤的系統(tǒng)監(jiān)控,只要本軟件在運行,,無論當前計算機在做什么,,都能監(jiān)測到用戶按鍵的行為并做出反應(yīng),這就要用到Hook技術(shù),。 Hook技術(shù)在很多特殊軟件中廣泛應(yīng)用,,如,金山詞霸的“取詞”功能,,就用到了Hook計技術(shù),。 鉤子的本質(zhì)是一段用以處理系統(tǒng)消息的程序,通過系統(tǒng)調(diào)用,,將其掛入系統(tǒng),。鉤子的種類很多,每種鉤子可以截獲并處理相應(yīng)的消息,,每當特定的消息發(fā)出,,在到達目的窗口之前,鉤子程序先行截獲該消息,、得到對此消息的控制權(quán),。此時在鉤子函數(shù)中就可以對截獲的消息進行加工處理,甚至可以強制結(jié)束消息的傳遞,。 從鉤子的本質(zhì)來看,,可以優(yōu)先截獲操作系統(tǒng)的各種消息進行處理,所以它幾乎無所不能,,因為windows的應(yīng)用程序都是基于消息驅(qū)動的,,應(yīng)用程序的操作都依賴于它所得到的消息的類型及內(nèi)容。 如果Hook過程在應(yīng)用程序中實現(xiàn),,若應(yīng)用程序不是當前窗口時,,該Hook就補齊作用;如果Hook在DLL中實現(xiàn),,程序在運行中動態(tài)調(diào)用它,,它能實時對系統(tǒng)進行監(jiān)控。根據(jù)需要,,我們采用的是在DLL中實現(xiàn)Hook的方式,。 ?。☉?yīng)用程序exe? 和DLL的區(qū)別所在) 文本文件存儲管理 字符被計算機處理時都是以二進制代碼的形式出現(xiàn)的,即一個字符對應(yīng)一個8位二進制數(shù),,這種二進制碼的集合就是所謂的ASCII碼,。 基本的ASCII碼有128個,最高位都是0,,對應(yīng)的十進制數(shù)是0-127,。鍵盤上的字符,如英文字母,、數(shù)字和一些常用符號,,使用基本ASCII部分。如數(shù)字“0”的ASCII碼用二進制數(shù)表示就是00110000(即十進制數(shù)48),。 擴展的ASCII碼有128個,,最高位是1,對應(yīng)的十進制數(shù)是128-255,。一些制表符和其他符號使用擴展的ASCII碼部分,。 為解決漢字的存儲和顯示問題,我國制定了國際GB2312,。據(jù)此規(guī)定,,一個漢字由2個擴展的ASCII碼組成,這種高位為1的雙字節(jié)漢字編碼就是漢字的機內(nèi)碼,,簡稱為內(nèi)碼,。例如,漢字“學(xué)”的機內(nèi)碼用二進制數(shù)表示就是11010001 10100111(即十進制數(shù)206 和167 ),,用十進制表示就是53671(206*256+167)。對于字符,,文本文件存儲的是它的ASCII碼,,對于漢字,文本文件存儲的是它的內(nèi)碼,,即兩位ASCII碼,,如字符串“0學(xué)0”,在文本文件中存儲的內(nèi)容是00110000 11010001 10100111 00110000 正確的文本文件讀寫過程 1.定義文件變量,;2.打開指定的文件,;3.向從文本文件中寫入信息;4.從文本文件中讀取信息,;5.關(guān)閉文件 1,、定義文件變量 定義文件變量格式:CStdioFile 文件變量; 例如,,定義一個名稱為f1的文件變量,,語句如下:CStdioFile f1; 2,、打開指定文件 可以直接通過CStdioFile的構(gòu)造函數(shù)來打開磁盤文件,同時可以用標志位指定打開方式(只讀,、只寫,、讀寫等): CStdioFile(LPCTSTR lpszFileName,UINT nOpenFlags); 其中,lpszFileName表示要打開的文件名,,可以是相對路徑或絕對路徑 nOpenFlags設(shè)置文件打開方式標志位,,可以指定用“|”連接多個標志位。下面是常用的打開標志: CFile::typeText:以文本文件的形式打開文件 CFile::typeBinary:以二進制文件的形式打開文件 CFile::modeCreate:如果指定文件名的文件不存在,,則新建文件,;如果文件存在并且沒有設(shè)置CFile::modeNoTruncate標志,則清空文件,。 CFile::modeNoTruncate:如果文件存在,,不把它的長度刪除為0(即不清空文件中的數(shù)據(jù))。 CFile::modeRead:以只讀方式打開文件 CFile::modeReadWrite:以可讀可寫方式打開文件 CFile::modeWrite:以只寫方式打開文件 CFile::shareDenyNone:文件打開后,,不禁止其他進程對文件的讀寫操作 CFile::shareExclusive:文件打開后,,禁止其他進程對文件的讀寫操作 CFile::shareDenyRead:文件打開后,禁止其他進程對文件的讀操作 CFile::shareDenyWrite:文件打開后,,禁止其他進程對文件的寫操作 此外,,可以不在構(gòu)造函數(shù)中打開文件,而僅僅調(diào)用空的構(gòu)造函數(shù)CStidoFile(),,然后用CStdioFile::Open()打開文件,。Open函數(shù)的前兩個參數(shù)和非空構(gòu)造函數(shù)的參數(shù)相同,其聲明如下: BOOL Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError=NULL); 第3個參數(shù)與打開失敗時的異常處理有關(guān),。 實例1:以只讀方式打開一個文件 步驟: 使用AppWizard創(chuàng)建一個對話框應(yīng)用程序,,刪除其自動產(chǎn)生的所有控件,添加一個Button控件,。雙擊控件,,在相應(yīng)的函數(shù)里添加代碼: char * pszFileName="C:\\myfile.txt"; CStdioFile myFile; CFileException fileException; if(!myFile.Open(pszFileName,CFile::modeCreate|CFil e::typeText|CFile::modeRead),&fileException) { TRACE("Can't open file %s, error = %u\n",pszFileName,fileException.m_cause); } 運行結(jié)果:如果C:\下沒有myfile.txt文件,則新生成該文件,。 3.向從文本文件中寫入信息 CStdioFile提供了函數(shù)WriteString來向文本文件中寫入文本,,WriteString函數(shù)的格式如下: void WriteString(LPCTSTR lpsz); WriteString的參數(shù)lpsz是一個以”\0”字符結(jié)束的字符串,要把這個字符串的內(nèi)容寫入文件,。 提示:使用WriteString函數(shù)時,,如果希望每執(zhí)行一次WriteString,文本文件中的內(nèi)容就會自動換行一次,,那么就需要在需要換行的地方輸出“\n”: myFile.WriteString(“第1行\(zhòng)n”),; 實例2:向文件中寫入文本 建立MFC基于對話框的程序,刪除自動添加的所有控件,,添加一個“確定”按鈕,,雙擊按鈕,,按默認添加事件函數(shù),雙擊按鈕,,在相應(yīng)的函數(shù)處添加如下代碼: char* pszFileName="C:\\myfile.txt"; CStdioFile myFile; CFileException fileException; if(myFile.Open(pszFileName,CFile::typeText|CFile:: modeCreate|CFile::modeReadWrite),&fileException) { myFile.WriteString("第1行\(zhòng)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); } 程序運行結(jié)果:C:\myfile.txt文件中內(nèi)容如下: 第1行 66,88.880 4.從文本文件中讀取信息 CStidoFile提供了函數(shù)ReadString來讀取文本,,ReadString有兩種形式,一種為: virtual LPTSTR ReadString(LPTSTR lpsz, UINIT nMax); ReadString函數(shù)的參數(shù)如下: lpsz :是用戶提供的一個指向字符串的指針,,它用來接受從文件讀出的文本,,以”\0”結(jié)束。 nMax是本次所允許讀入的文本字符個數(shù),,不計“\0”字符,,也就是說最多能讀入nMax-1個文本字符。 ReadString的返回值是一個LPTSTR類型的指針,,它指向從文件讀出的文本字符串,,如果到達文件尾,則返回NULL,。 ReadString的另一種形式為: BOOL ReadString(CString& rString); 參數(shù)rString用來容納從文件讀出的文本,。 CString版本忽略回車換行符,返回值是一個布爾值,。如果返回值為FALSE,,表示因到達文件尾而沒有讀到任何字符。 提示:每執(zhí)行一次ReadString,,就會自動從文本文件中讀取一行數(shù)據(jù),,同時文件操作指針會自動跳轉(zhuǎn)到下一行。 實例3:從文件中讀取文本信息 步驟:創(chuàng)建基于對話框的MFC程序,,刪除所有自動添加的控件,,添加按鈕控件,為按鈕添加事件,,并在相應(yīng)的函數(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(); 5.關(guān)閉文件 對文件的操作完成后,使用CloseFile關(guān)閉文件,。 函數(shù)CStdioFile::Close關(guān)閉一個文件,一般一個文件使用完畢就應(yīng)該關(guān)閉它: myFile.Close(); 錯誤的文本文件讀寫過程 在讀寫文本文件的時候,,最常見的錯誤是---操作文件不存在,。這種錯誤產(chǎn)生的典型原因有: 1.路徑錯誤 char * pszFileName="C:\\Windows\\MyFile.txt"; CStdioFile myFile; CFileException fileException; if(!myFile.Open(pszFileName,CFile::modeCreate|CFil e::typeText|CFile::modeReadWrite),&fileException) { //文件操作代碼 } else { TRACE("Can't open file %s, error = %u\n",pszFileName,fileException.m_cause); } myFile.Close(); 由于將文件變量與一個絕對路徑的文件名關(guān)聯(lián),而程序的數(shù)據(jù)通常存儲在相對路徑下,,所以一旦相對路徑和相對路徑不一致時,,就會出錯。 舉例而言,,上一段程序本意是想從windows的安裝目錄下面的MyTextFile.txt文件中讀取一行數(shù)據(jù),,但是如果操作系統(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::mod eCreate|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.操作文件不存在 如果應(yīng)用程序所有路徑下面不存在MyFile.txt文件,那么在WriteString寫入信息時就會出錯,。 解決辦法就是在程序中打開文件前要檢查是否存在此文件,。如下程序: CString strFileTitle="MyFile.txt"; CFileFind finder; if(finder.FindFile(strFileTitle)) { CStdioFile myFile; CFileException fileException; if(myFile.Open(lpBuffer,CFile::typeText|CFile::mod eCreate|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.超越文件權(quán)限進行讀寫操作 在打開文件的過程中,通過參數(shù)指定了文件的讀寫權(quán)限,,如果讀寫的操作沒有和相應(yīng)的權(quán)限對應(yīng),,就會出現(xiàn)錯誤。 下面的程序就是典型的忽略了文件操作權(quán)限的例子: CString strFileTitle="MyFile.txt"; CStdioFile myFile; CFileException fileException; if(myFile.Open(strFileTitle,CFile::typeText|CFile: :modeCreate|CFile::NoTruncate|CFile::modeRead),&fil eException) { //文件操作代碼 myFile.WriteString("測試!"); } else { TRACE("Can't open file %s,error=%u\n",strFileTitle,fileException.m_cause) ; } myFile.Close(); |
|