C中的文件處理函數並不很多,而常用的,似乎更少。
函數不難,但並不代表文件處理也不難。似乎又要有點跑題了,我總是喜歡跑題。上幾天做夢,夢到我掉到月球上去啦……
對文件的操作,無非就是打開、讀寫、調整讀寫偏移指針以及關閉,似乎麼什可說的,也許事實也的確如此。還是讓我們來看一段經典代碼吧,這代碼可是我自己寫的。
FILE* fp = fopen("test.txt", "r"); assert(fp); //打開文件,給一個斷言,這是一種好習慣
fseek(fp, 0, SEEK_END); //把偏移指針指向文件的結尾
unsigned int nlen = ftell(fp); //返回當前的偏移指針,也就是返回剛剛設定的文尾位置
fseek(fp, 0, SEEK_SET); //把讀寫偏移指針指向文件的開頭
char* const _psz = (char*)malloc(nlen + 1); //申請一段堆內存,這裏的_psz爲什麼要被const修飾呢?
unsigned int size = fread(_psz, sizeof(char), nlen, fp); //讀出文件的內容
_psz[size] = '\0'; //注意,必須要在字符串的結尾處添加結束標誌,否則,哼哼!
fclose(fp); //關閉文件
…… //東搞搞,西搞搞
free(_psz); //歸還堆內存
實在是太簡單了是吧?是的,我正這樣認爲呢。
在讀文件的時候,有點東西還是要說說的。因爲我們都聽說過,文件有兩種格式,一種是文本,一種是二進制。文本文件,當然,我們不想說什麼了,但二進制文件的讀寫,卻值得一提。二進制的文件這樣打開:
FILE* fp = fopen("test.exe", "rb"); assert(fp);
當然,可執行文件只不過是二進制文件的一個代表,在使用讀寫標誌的時候,我們需要"b"後綴,表明打開的是二進制的文件。其實,這不是關鍵,而正真關鍵的部分是對文件的讀寫,這份代碼有點冗餘,但不寫又怕給人鬧出強迫症。
fseek(fp, 0, SEEK_END); //獲取文件大小
size_t nlen = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char* const _psz = (unsigned char*)malloc(nlen + 1); //顯然,申請的內存應該是BYTE格式
fread(_psz, sizeof(unsigned char), nlen, fp); //由於是二進制的文件,我們不必再對內存做處理
fclose(fp);
通常,這種用法不常見,而更多的對二進制文件的讀寫,是出現在socket上。比如,我們要從網上更新一個可執行文件,那麼必須使用二進制的打開標誌,否則,你得到的只不過是一串小的可憐的碎片。最簡單的從網上下載文件,我們可以使用MFC的CInternetSession封裝類,簡單的用法如下:
CString strUrl = "http://hi.baidu.com/idealsoft/tools/test.exe"; //看好這個200K的exe文件
CInternetSession sess; //我建議大家對象全部用小寫,感覺很實在,小而強大嘛!
CStdioFile* pFile = sess.OpenURL(strUrl); ASSERT(pFile);
我們照例還是獲得pFile的大小,假如說是nlen,之所以我沒有使用函數來獲得,其實有我的苦衷,如果讀者有興趣的話,可以看MFC分類下的文章《CFile如何使用,用法舉例》,反正,不管如何,假如我們現在已經獲得這個網絡文件的大小了,下面立即讀取。
char* const _psz = new char[nlen + 1]; ASSERT(_psz);
unsigned int size = pFile->Read(_psz, nlen);
…… //好,現在文件已經獲取了,幹一些自己想幹的事情
什麼都沒有幹成!
開始查找原因,但什麼都沒有找到!
開始懷疑網絡文件有問題!
開始懷疑MFC有問題!
開始懷疑VC有問題!
開始懷疑自己有問題!
的確有問題,問題在哪?我們先看看OpenURL的聲明吧,源碼始終是我們唯一可以依賴的!
CStdioFile* OpenURL(LPCTSTR pstrURL, DWORD dwContext = 1, DWORD dwFlags = INTERNET_FLAG_TRANSFER_ASCII, LPCTSTR pstrHeaders = NULL, DWORD dwHeadersLength = 0);
我們之前已經說過了,對於二進制文件的讀取,一定要用二進制標誌,CInternetSession也同樣不能例外。
CStdioFile* pFile = pSession->OpenURL(pczUrl, 1, INTERNET_FLAG_TRANSFER_BINARY);
這纔是正確的寫法,而在OpenURL這個函數的聲明中,pstrURL以後的參數都被賦予了默認值。再看dwFlags這個標誌位,原來它默認的是ASCII碼,也就是文本文件,可是我們要下載的,那是.exe文件,也就是二進制文件,所以好像搞錯了,而對於這個函數的第二個參數dwContext,到底是什麼意思?這不用你管,說實話,我也不太清楚,所以你想知道的,也是我想知道的,既然微軟已經把它填了一個解釋的連自己舌頭都要繞斷的默認值,那麼我們也就隨大溜吧,不過我這裏可以先偷偷的告訴你,它的英文解釋是:An application-defined value passed with the returned handle in callback,也就是:與回調中的返回句柄一同傳遞的一個應用程序定義的值!!!汗流浹背啊,不知所云,如果你想探個究竟,MSDN與源碼正在恭候你。
好,切入主題。
這樣一來,文件可以順利下載了,一切都很令你滿意,你開始有點得意的埋怨你剛剛的草率與魯莽,因爲一切都很正常。
這樣的結果,已經能夠令你滿意,你現在要做的是:
…… //東搞一下,西搞一下
delete[] _psz; //釋放堆內存
這樣,大功告成了,你準備接受老闆的讚賞,但得到的卻是兩個耳光!!
你憤恨,不滿,準備離開這裏。
真的大功告成了嗎?其實是大失告敗,現在,你一定會睜大眼睛,等待下文吧,對不起,我不是一個隨便的人,雖然隨便起來我不是人。
好,請您在《CFile如何使用,用法舉例》中尋找答案。