# 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 全书小结