首页 > 代码库 > c++Builder 下的文件及目录操作
c++Builder 下的文件及目录操作
转自 http://blog.csdn.net/ktcserver/article/details/936329
一、判断目录是否存在:
C++ Builder中提供了检查文件是否存在的函数FileExists,indows 程序实现如下:
设char *Dir为带判断的目录
bool Exist; // 最后结果,表示目录是否存在
if(Dir[strlen(Dir)]==‘//‘)Dir[strlen(Dir)-1]=‘/0‘; // 先删除最后的“/”
WIN32_FIND_DATA wfd; // 查找
HANDLE hFind=FindFirstFile(Dir,&wfd);
if(hFind==INVALID_HANDLE_VALUE)Exist=false; // 没有找到配备,目录肯定不存在
else
{
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 检查找到的结果是否目录
Exist=true; // 是目录,目录存在
else
Exist=false; // 是目录,目录不存在
FindClose(hFind);
}
二、打开目录选择对话框选择一个目录:
大多专业软件在要求输入目录的编辑框旁都放了一个按钮,点击后打开一个目录窗口,很多编程爱好者也希望能掌握这个方法。实现这个功能要调用Windows API函数SHBrowseForFolder,完整声明为WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi),返回一个ITEMIDLIST类型的指针,通过这个指针调用函数SHGetPathFromIDList可以确定所选择的目录的全名称。入参为BROWSEINFO结构的指针,这个结构较为复杂,成员如下所示:
HWND hwndOwner; // 拥有对话框的窗口,可以设置为Application->Handle
LPCITEMIDLIST pidlRoot; // ITEMIDLIST类型的指针,表示在哪个路径下选择,一般可以设置为NULL
LPSTR pszDisplayName; // 选择后,所选目录的名称(不包含父级目录)被拷贝到这个指针指向的位置
LPCSTR lpszTitle; // 作为标题显示在对话框中目录树的上面,可以根据实际情况设置
UINT ulFlags; // 标志位,有点复杂,一般设置为BIF_RETURNONLYFSDIRS
BFFCALLBACK lpfn; // 回调函数,一般不用,设置为NULL
LPARAM lParam; // 预定义的对话框传递给回调函数的值
int iImage; // 与所选目录相关联的图标在系统图标集合中的索引
可以看出,使用函数SHBrowseForFolder还真麻烦,普通爱好者掌握它确实有一定的难度,现给出完整程序段如下:
#include <shlobj.h> // 必须包含的头文件
char SelectedDir[MAX_PATH]; // 最终结果
BROWSEINFO bi; // 入参
char FolderName[MAX_PATH]; // 所选目录名称,例如选择C:/Windows/Font,则为Font
LPITEMIDLIST ItemID; // 所选目录的系统标志指针
memset(SelectedDir, 0, MAX_PATH); // 初始化最终结果
memset(&bi, 0, sizeof(BROWSEINFO)); // 初始化入参所有数据
bi.hwndOwner = Application->Handle;
bi.pszDisplayName = FolderName;
bi.lpszTitle = "请选择目录"; // 改成自己希望的
bi.ulFlags=BIF_RETURNONLYFSDIRS;
ItemID = SHBrowseForFolder(&bi); // 调用函数,打开目录选择对话框
if(ItemID)
{
SHGetPathFromIDList(ItemID, SelectedDir); // 获取所选目录的全名
GlobalFree(ItemID); // 返回的ItemID占用了系统资源,不要忘了释放
}
三、直接建立多级目录:
Windows API提供了建立目录的函数CreateDirectory,但是调用前要保证父目录必须存在,否则会失败。其实,有时越级建立多级目录很有用,因为在建立目录特别是建立多层目录时,层层加以判断会大大地增加程序的复杂程度。如何实现这个功能呢?本人用递归方法设计了一个可以直接建立多级目录的函数,现说明如下,供各位朋友参考。
bool MakeDirectoryEx(const AnsiString &P) // 入参为打算创建的目录名,根据操作结果返回"true"或"false"
{
if(P.IsEmpty())return false;
int len=P.Length();
char *Path=P.c_str();
if(Path[len-1]==‘//‘)
{
len--;
Path[len]=‘/0‘;
} // 删除末尾的"/"
AnsiString Dir=Path;
// 分开父目录和本身目录名称
AnsiString Parent;
for(int i=len-1;i>0;i--)
{
if(Dir.IsPathDelimiter(i))
{
Parent=Dir.SubString(0,i);
break;
}
}
if(Parent.IsEmpty())return false; // 目录名称错误
bool Ret=true;
if(Parent.Length()>3) // 如果长度小于3,表示为磁盘根目录
Ret=DirectoryExistEx(Parent.c_str());// 检查父目录是否存在
if(!Ret)Ret=MakeDirectoryEx(Parent); // 父目录不存在,递归调用创建父目录
if(Ret) // 父目录存在,直接创建目录
{
SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=0;
Ret=CreateDirectory(Path,&sa);
}
return Ret;
}
可以看出基本方法是:
先检查父目录是否存在,这里用到的函数DirectoryExistEx可以按照前面介绍的方法设计;
如果父目录存在,则直接创建目录,否则自我调用创建父目录。
四、直接删除整个目录:
在DOS下有一个Deltree命令,用来删除整个目录,这是一个很有用的功能,可惜,Windows API提供的函数RemoveDirectory只能删除控目录,就像DOS的RD命令一样。编程实现这个功能同样需要递归方法,基本流程是:
查找目录下的所有文件和目录,即调用API函数FindFirstFile、FindNextFile(*.*)
如果找到文件,则强制删除。所谓强制删除,即删除前先调用SetFileAttributes把它的属性设置为Normal,然后调用DeleteFile删除它。
如果找到目录,则进行自我调用,即开始递归过程。
如果没有找到目录,即表示为控目录,调用RemoveDirectory直接删除。
具体程序代码如下:
bool DeleteDirectoryEx(const AnsiString &P)
{
if(P.IsEmpty() || P.Length()<4)return false; // 参数长度必须大于3,即不能为磁盘根目录或空白
int len=P.Length();
char *Path=P.c_str();
AnsiString Dir=Path;
if(Path[len-1]!=‘//‘)Dir=Dir+‘//‘;
AnsiString Files=Dir+"*.*";
WIN32_FIND_DATA wfd;
HANDLE hFind=FindFirstFile(Files.c_str(),&wfd);
bool Ret=true;
AnsiString Tmp;
if(hFind!=INVALID_HANDLE_VALUE)
{
bool bFind=true;
while(bFind)
{
if(wfd.cFileName[0]!=‘.‘) // . ..
{
Tmp=Dir+wfd.cFileName;
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ // 删除所有子目录
Ret=Ret&&DeleteDirectoryEx(Tmp.c_str(),false);
}else
{ // 删除所有文件
SetFileAttributes(Tmp.c_str(),FILE_ATTRIBUTE_NORMAL);
Ret=Ret&&DeleteFile(Tmp.c_str());
}
}
bFind=FindNextFile(hFind,&wfd);
}
FindClose(hFind);
}
if(Ret)return RemoveDirectory(Path);
return false;
}
直接建立多级目录可以用ForceDirectories
比如ForceDirectories("C://111//222//333");
即使不存在C:/111这个目录,也会创建成功。
ExpandFileName() 返回文件的全路径(含驱动器、路径)
ExtractFileExt() 从文件名中抽取扩展名
ExtractFileName() 从文件名中抽取不含路径的文件名
ExtractFilePath() 从文件名中抽取路径名
ExtractFileDir() 从文件名中抽取目录名
ExtractFileDrive() 从文件名中抽取驱动器名
ChangeFileExt() 改变文件的扩展名
ExpandUNCFileName() 返回含有网络驱动器的文件全路径
ExtractRelativePath() 从文件名中抽取相对路径信息
ExtractShortPathName() 把文件名转化为DOS的8·3格式
MatchesMask() 检查文件是否与指定的文件名格式匹配
CreateDir() 创建新的子目录
DeleteFile() 删除文件
DirectoryExists() 判断目录是否存在
DiskFree() 获取磁盘剩余空间
DiskSize() 获取磁盘容量
FileExists() 判断文件是否存在
FileGetAttr() 获取文件属性
FileGetDate() 获取文件日期
GetCurrentDir() 获取当前目录
RemoveDir() 删除目录
SetCurrentDir() 设置当前目录
下面就把这些函数作一一介绍:
⑴CreateDir()
原型:extern PACKAGE bool __fastcall CreateDir(const System::AnsiString Dir);
功能:建立子目录,如果成功返回true,否则返回false
参数:Dir:要建立的子目录的名字
例:Create("ASM");//在当前目录下建立一个名为ASM的子目录
⑵DeleteFile()
原型:extern PACKAGE bool __fastcall DeleteFile(const System::AnsiString FileName);
功能:删除文件,如果成功返回true,否则返回false
参数:FileName:要删除的文件名
例:if(OpenDialog1->Execute())DeleteFile(OpenDialog1->FileName);
⑶DirectoryExists()
原型:extern PACKAGE bool __fastcall DirectoryExists(const System:: AnsiString Name);
功能:检测目录是否存在,如果存在返回true,否则返回false
参数:Name:要检测的目录名
例:if(!DirectoryExists("ASM"))CreateDir("ASM");//如果ASM这个目录不存在则创建之
⑷DiskFree()
原型:extern PACKAGE __int64 __fastcall DiskFree(Byte Drive);
功能:检测磁盘剩余空间,返回值以字节为单位,如果指定的磁盘无效,返回-1
参数:Drive:磁盘的代号,0表示当前盘, 1=A,2=B,3=C 以此类推
例:ShowMessage(DiskFree(0));//显示当前盘的剩余空间
⑸DiskSize()
原型:extern PACKAGE __int64 __fastcall DiskSize(Byte Drive);
功能:检测磁盘容量,返回值以字节为单位,如果指定的磁盘无效,返回-1
参数:Drive:磁盘的代号,0表示当前盘, 1=A,2=B,3=C 以此类推
例:ShowMessage(DiskFree(0));//显示当前盘的容量
⑹FileExists()
原型:extern PACKAGE bool __fastcall FileExists(const AnsiString FileName);
功能:检测文件是否存在,如果存在返回true,否则返回false
参数:FileName:要检测的文件名
例:if(FileExists("AAA.ASM"))DeleteFile("AAA.ASM");
⑺FileGetAttr()
原型:extern PACKAGE int __fastcall FileGetAttr(const AnsiString FileName);
功能:取得文件属性,如果出错返回-1
返回值如下表,如果返回$00000006表示是一个具有隐含和系统属性的文件(4+2)
常量 值 含义
faReadOnly $00000001 只读文件
faHidden $00000002 隐含文件
faSysFile $00000004 系统文件
faVolumeID $00000008 卷标
faDirectory $00000010 目录
faArchive $00000020 归档文件
例:if(FileGetAttr("LLL.TXT")&0x2)ShowMessage("这是一个有隐含属性的文件");
与此对应的有FileSetAttr() ,请自已查阅帮助系统
⑻FileGetDate()
原型:extern PACKAGE int __fastcall FileGetDate(int Handle);
功能:返回文件的建立时间到1970-1-1日0时的秒数
参数:Handle:用FileOpen()打开的文件句柄。
例:
int i=FileOpen("C://autoexec.bat",fmOpenRead);
ShowMessage(FileGetDate(i));
FileClose(i);
与此对应的有FileSetDate(),请自已查阅帮助系统
⑼GetCurrentDir()
原型:extern PACKAGE AnsiString __fastcall GetCurrentDir();
功能:取得当前的目录名
例:ShowMessage(GetCurrentDir());
⑽RemoveDir()
原型:extern PACKAGE bool __fastcall RemoveDir(const AnsiString Dir);
功能:删除目录,如果成功返回true,否则返回false
参数:Dir:要删除的目录名
例:if(DiectoryExists("ASM"))RemoveDir("ASM");
⑾SetCurrentDir()
原型:extern PACKAGE bool __fastcall SetCurrentDir(const AnsiString Dir);
功能:设置当前目录,如果成功返回true,否则返回false
参数:Dir:要切换到的目录名
例:SetCurrentDir("C://WINDOWS");