# 14.1 文件類和函數
wxWidgets提供了一系列的平臺無關的文件處理功能.在概覽所有文件函數之前,我們先來看看幾個主要的類.
wxFile和wxFFile
wxFile類可以用來處理底層的文件輸入輸出.它封裝了常用的用于操作整數文件標識符的標準C操作(打開關閉,讀寫,移動游標等),但是和標準C不同的是,它使用wxLog類來報告錯誤并且在析構函數中自動關閉文件.而wxFFile則提供緩沖的輸入輸出操作,內部使用的是FILE類型的指針.
你可以通過下面的方法創建一個wxFile對象:使用默認構造函數然后調用Create或者Open函數;或者直接在構造函數中指明文件名和打開模式(wxFile::read, wxFile::write或wxFile::read_write);或者直接使用已經存在的整數文件描述符(相關構造函數或者默認構造函數加 Attach函數).Close函數關閉當前使用的文件,文件也將在析構函數中視需要進行關閉.
從文件中讀取數據使用Read函數,參數為一個void*和一個緩沖區大小,返回實際讀取的數值大小或者 wxInvalidOffset如果讀取過程發生錯誤.使用Write函數將指定大小的void*類型的緩沖區寫入文件,如果你希望寫操作立即寫到物理文件,你需要使用Flush函數.
Eof函數用來檢測當前的文件指針是否位于文件結尾的位置(而wxFFile的Eof函數只有在其讀操作越過了文件結尾的時候才返回True).你可以用Length函數返回文件的長度.
Seek和SeekEnd函數將文件指針移動到相對于文件開始或者文件結尾的一個偏移位置.Tell函數返回wxFileOffset類型的當前文件指針位置,這個類型在支持64位操作系統上是64位整數,否則是32位整數.
Access函數是一個靜態函數,用來判斷某個文件是否可以以指定的模式打開,而Exists函數則用來判斷指定的文件是否存在.
下面的代碼演示了怎樣使用wxFile打開一個文件并且將其內容讀取到一個數組中:
```
#include "wx/file.h"
if (!wxFile::Exists(wxT("data.dat")))
return false;
wxFile file(wxT("data.dat"));
if ( !file.IsOpened() )
return false;
//文件大小
wxFileOffset nSize = file.Length();
if ( nSize == wxInvalidOffset )
return false;
// 將所有內容讀取到一個數組中
wxUint* data = new wxUint8[nSize];
if ( fileMsg.Read(data, (size_t) nSize) != nSize )
{
delete[] data;
return false;
}
file.Close();
```
下面的代碼則演示了怎樣將一個文本框的所有內容寫入到文件中:
```
bool WriteTextCtrlContents(wxTextCtrl* textCtrl,
const wxString& filename)
{
wxFile file;
if (!file.Open(filename, wxFile::write))
return false
int nLines = textCtrl->GetNumberOfLines();
bool ok = true;
for ( int nLine = 0; ok && nLine < nLines; nLine++ )
{
ok = file.Write(textCtrl->GetLineText(nLine) +
wxTextFile::GetEOL());
}
file.Close();
return ok;
}
```
wxTextFile
wxTextFile提供了一種非常直接的方式來以行為單位讀取和寫入小型的文本文件.
使用Open函數將這個文本文件讀取到內存中并且以行為單位進行分割,使用Write函數寫回到文本文件.你可以使用GetLine函數或者直接按照數組的方式操作某個特定的行.或者使用GetFirstLine,GetNextLine和GetPrevLine進行遍歷.AddLine 和InsertLine用來增加新行,RemoveLine用來移除特定的行,Clear函數則用來清空所有的行.
下面的例子演示了將文本文件中的每一行都增加一個前導文本的方法:
```
#include "wx/textfile.h"
void FilePrepend(const wxString& filename, const wxString& text)
{
wxTextFile file;
if (file.Open(filename))
{
size_t i;
for (i = 0; i < file.GetLineCount(); i++)
{
file[i] = text + file[i];
}
file.Write(filename);
}
}
```
wxTempFile
wxTempFile是wxFile的一個派生類,它使用臨時文件來寫入數據,數據在Commit函數被調用之前不會被寫入.如果你需要寫一些用戶數據,你可以將其寫在臨時文件里,它的好處是:如果遇到突然的斷電或者應用程序不可知錯誤或者其它大的錯誤時,臨時文件不會對磁盤上的文件系統造成任何傷害.
提示:文檔/視圖框架在創建一個輸出流然后調用SaveObject的時候沒有使用臨時文件.你可以嘗試重載其 DoSaveDocument函數,在其中構建一個wxFileOutputStream并且讓其使用一個臨時文件wxTempFile對象,在全部數據寫完以后,調用Sync函數和Commit函數將其寫入臨時文件.
wxDir
wxDir是一個輕便的等價于Unix上的open/read/closedir函數的類,它支持枚舉目錄中的所有文件.wxDir既支持枚舉目錄中的文件,也支持枚舉目錄中的子目錄.它還提供了一個靈活的遞歸枚舉文件的方法Traverse函數,和另外一種簡單的方法: GetAllFiles函數.
首先,你需要調用Open函數打開一個目錄(或者通過構造函數直接賦值),然后調用GetFirst函數,參數為一個指向字符串類型的指針用來接收找到的文件名,一個可選的文件通配符(默認為所有文件)和一個可選的選項.然后調用GetNext函數直到其返回False.文件通配符可以是固定的文件名以及包含"*(匹配任意字符)"和"?"(匹配單個字符)的通配符.選項參數可選的值為:wxDIR_FILES(所有文件), wxDIR_DIRS(所有文件夾),wxDIR_HIDDEN(隱藏文件)以及wxDIR_DOTDOT("."和"..")以及它們的組合,默認值為除了最后一項的所有文件.
下面是一個例子:
```
#include "wx/dir.h"
wxDir dir(wxGetCwd());
if ( !dir.IsOpened() )
{
// 如果遇到這個情況,wxDir已經顯示了一個出錯信息.
// 所以直接返回就可以了
return;
}
puts("Enumerating object files in current directory:");
wxString filename;
wxString filespec = wxT("*.*");
int flags = wxDIR_FILES|wxDIR_DIRS;
bool cont = dir.GetFirst(&filename, filespec, flags);
while ( cont )
{
wxLogMessage(wxT("%s\n"), filename.c_str());
cont = dir.GetNext(&filename);
}
```
如同上面注釋中說的那樣,如果wxDir打開的時候出現錯誤,將會彈出一個錯誤消息,如果想禁止這個消息,你可以臨時通過設置wxLogNull的方法,如下所示:
```
{
wxLogNull logNull;
wxDir dir(badDir);
if ( !dir.IsOpened() )
{
return;
}
}
```
wxFileName
wxFileName用來處理文件名.它可以分解和組合文件名,還提供了很多額外的操作,其中某些為靜態函數.下面演示了一些例子,更多的功能請參考wxWidgets的手冊:
```
#include "wx/filename.h"
// 使用字符串創建文件名
wxFileName fname(wxT("MyFile.txt"));
// Normalize,在windows平臺上這個函數的動作包括
// 確保文件名為長文件名格式
fname.Normalize(wxPATH_NORM_LONG|wxPATH_NORM_DOTS|wxPATH_NORM_TILDE|
wxPATH_NORM_ABSOLUTE);
// 返回全路徑
wxString filename = fname.GetFullPath();
// 返回相對于當前目錄的路徑
fname.MakeRelativeTo(wxFileName::GetCwd());
// 文件存在嗎?
bool exists = fname.FileExists();
// 另外一個文件存在嗎?
bool exists2 = wxFileName::FileExists(wxT("c:\\temp.txt"));
// 返回文件名的名稱部分
wxString name = fname.GetName();
// 返回路徑部分
wxString path = fname.GetPath();
// 在windows系統上返回相應的短路徑文件名,其它平臺上
// 返回本身.
wxString shortForm = fname.GetShortPath();
// 創建一個文件夾
bool ok = wxFileName::Mkdir(wxT("c:\\thing"));
```
File Functions
下表列出了一些有用的靜態文件操作函數,它們定義在頭文件wx/filefn.h中.請同時參考wxFileName類,尤其是其中的靜態函數部分,比如wxFileName::FileExists函數.
| wxDirExists(dir) | 是否目錄存在. 參考wxFileName::DirExists |
|:--- |:--- |
| wxConcatFiles(f1, f2, f3) | 將f1和f2合并為f3, 成功時返回True. |
| wxCopyFile(f1, f2, overwrite) | 拷貝f1到f2,可選擇是否覆蓋已存在的f2.返回Bool型 |
| wxFileExists(file) | 測試是否文件存在. 參考wxFileName::FileExists |
| wxFileModificationTime(file) | 返回文件修改時間(time_t類型). 參考wxFileName::GetModificationTime,它返回wxDateTime類型 |
| wxFileNameFromPath(file) | 返回文件全路徑的文件名部分. 推薦使用wxFileName::SplitPath函數 |
| wxGetCwd() | 返回當前工作目錄. 參考wxFileName::GetCwd |
| wxGetdiskSpace (path, total, free) | 返回指定路徑所在的磁盤的全部空間和空閑空間,空間為wxLongLong類型. |
| wxIsAbsolutePath(path) | 測試指定的路徑是否為絕對路徑. |
| wxMkdir(dir, permission=777) | 創建一個目錄,其父目錄必須存在,可選指定目錄訪問掩碼.返回bool型 |
| wxPathOnly(path) | 返回給定全路徑的目錄部分. |
| wxRemoveFile(file) | 刪除文件,成功時返回True. |
| wxRenameFile(file1, file2) | 重命名文件,成功時返回True.如果需要進行文件拷貝,則直接返回False. |
| wxRmdir(file) | 移除空目錄,成功時返回True. |
| wxSetWorkingDirectory(file) | 設置當前工作目錄,返回bool型. |
wxWidgets同樣提供了許多函數來封裝標準C函數,比如: wxFopen, wxFputc和wxSscanf,這些函數沒有在手冊中記錄,不過你應該可以在include/wx/wxchar.h中找到它們.
另外一個有用的宏是wxFILE_SEP_PATH,它代表了不同平臺上的路徑分割符,比如在windows平臺上它代表"\",而在Unix平臺上則代表"/".
- 第一章 介紹
- 1.1 為什么要使用wxWidgets?
- 1.2 wxWidgets的歷史
- 1.3 wxWidgets社區
- 1.4 wxWidgets和面向對象編程
- 1.5 wxWidgets的體系結構
- 1.6 許可協議
- 第一章小結
- 第二章 開始使用
- 2.1 一個小例子
- 2.2 應用程序類
- 2.3 Frame窗口類
- 2.4 事件處理函數
- 2.5 Frame窗口的構造函數
- 2.6 完整的例子
- 2.7 wxWidgets程序一般執行過程
- 2.8 編譯和運行程序
- 第二章小結
- 第三章 事件處理
- 3.1 事件驅動編程
- 3.2 事件表和事件處理過程
- 3.3 過濾某個事件
- 3.4 掛載事件表
- 3.5 動態事件處理方法
- 3.6 窗口標識符
- 3.7 自定義事件
- 第三章小結
- 第四章 窗口的基礎知識
- 4.1 窗口解析
- 4.2 窗口類概覽
- 4.3 基礎窗口類
- 4.4 頂層窗口
- 4.5 容器窗口
- 4.6 非靜態控件
- 4.7 靜態控件
- 4.8 菜單
- 4.9 控制條
- 第四章小結
- 第五章繪畫和打印
- 5.1 理解設備上下文
- 5.2 繪畫工具
- 5.3 設備上下文中的繪畫函數
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas繪制三維圖形
- 第五章小節
- 第六章處理用戶輸入
- 6.1 鼠標輸入
- 6.2 處理鍵盤事件
- 6.3 處理游戲手柄事件
- 第六章小結
- 第七章使用布局控件進行窗口布局
- 7.1 窗口布局基礎
- 7.2 窗口布局控件
- 7.3 使用布局控件進行編程
- 7.4 更多關于布局的話題
- 第七章小結
- 第八章使用標準對話框
- 8.1信息對話框
- 8.2 文件和目錄對話框
- 8.3 選擇和選項對話框
- 8.4 輸入對話框
- 8.5 打印對話框
- 第八章小結
- 第九章創建定制的對話框
- 9.1 創建定制對話框的步驟
- 9.2 一個例子:PersonalRecordDialog
- 9.3 在小型設備上調整你的對話框
- 9.4 一些更深入的話題
- 9.5 使用wxWidgets資源文件
- 第九章小結
- 第十章使用圖像編程
- 10.1 wxWidgets中圖片相關的類
- 10.2 使用wxBitmap編程
- 10.3 使用wxIcon編程
- 10.4 使用wxCursor編程
- 10.5 使用wxImage編程
- 10.6 圖片列表和圖標集
- 10.7 自定義wxWidgets提供的小圖片
- 第十章小結
- 第十一章剪貼板和拖放操作
- 11.1 數據對象
- 11.2 使用剪貼板
- 11.3 實現拖放操作
- 第十一章小結
- 第十二章高級窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 編寫自定義的控件
- 第十二章小結
- 第十三章數據結構類
- 13.1 為什么沒有使用STL?
- 13.2 字符串類型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存儲和使用日期和時間
- 13.7 其它常用的數據類型
- 第十三章小結
- 第十四章文件和流操作
- 14.1 文件類和函數
- 14.2 流操作相關類
- 第十四章小結
- 第十五章內存管理,調試和錯誤處理
- 15.1 內存管理基礎
- 15.2 檢測內存泄漏和其它錯誤
- 15.3 構建自防御的程序
- 15.4 錯誤報告
- 15.5 提供運行期類型信息
- 15.6 使用wxModule
- 15.7 加載動態鏈接庫
- 15.8 異常處理
- 15.9 調試提示
- 第十五章小結
- 第十六章編寫國際化程序
- 16.1 國際化介紹
- 16.2 從翻譯說起
- 16.3 字符編碼和Unicode
- 16.4 數字和日期
- 16.5 其它媒介
- 16.6 一個小例子
- 第十六章小結
- 第十七章編寫多線程程序
- 17.1 什么時候使用多線程,什么時候不要使用
- 17.2 使用wxThread
- 17.3 用于線程同步的對象
- 17.4 多線程的替代方案
- 第十七章小結
- 第十八章使用wxSocket編程
- 18.1 Socket類和功能概覽
- 18.2 Socket及其基本處理介紹
- 18.3 Socket標記
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小結
- 第十九章使用文檔/視圖框架
- 19.1 文檔/視圖基礎
- 19.2 文檔/視圖框架的其它能力
- 19.3 實現Undo/Redo的策略
- 第十九章小結
- 第二十章完善你的應用程序
- 20.1 單個實例和多個實例
- 20.2 更改事件處理機制
- 20.3 降低閃爍
- 20.4 實現聯機幫助
- 20.5 解析命令行參數
- 20.6 存儲應用程序資源
- 20.7 調用別的應用程序
- 20.8 管理應用程序設置
- 20.9 應用程序安裝
- 20.10 遵循用戶界面設計規范
- 20.11 全書小結