Windows Mobile 5Windows Mobile 6Windows MobileWin32Visual Studio 2008Visual Studio 2005中级开发Visual StudioWindowsC++
目录文件列表实用程序
一篇关于递归列出给定目录中所有文件的方法的文章。
引言
我遇到过无数次,日常使用的实用功能根本无法使用,程序员不得不反复编写和重写它们。 这是我系列文章中的第一篇,旨在提供一系列常用的函数,并提供示例应用程序说明如何使用它们,希望它们对众多开发人员有用,就像它们对我一样有用。
其中一个函数是获取所有文件(它们的绝对路径)的列表,给定一个起始目录,并可以选择递归搜索子目录,或者只输出给定目录下的文件。
我发现这在许多需要出于某种原因遍历每个文件的项目中非常有用。
背景
这个函数是多年前开发的,当时我偶然遇到了一系列需要读取给定目录中每个文件的项目,并且还要实时提供进度信息,例如,当前正在处理哪个文件、文件总数和已处理的文件数。 从那时起,我可能在几十个项目中使用过这个函数。
Using the Code
按照以下简单步骤在您的项目中使用该代码
- 将文件 Util.h 和 Util.cpp 添加到您的 Visual Studio C++ 项目(或任何其他类型的项目,我从未在 Visual Studio C++ 项目之外的任何其他项目中使用过该代码,因此任何关于在其他 C++ 项目中使用它的输入都非常感谢)。
- 在您打算使用此功能的 *.cpp 文件的顶部部分添加行
#include "Util.h"
。 - 声明一个
_tstring
的向量:vector <_tstring> vecstrFileList;
。 - 使用所需的参数调用静态函数 "
GetFileList()
"。 - 该向量现在将包含在指定目录中找到的所有文件路径,向量的每个元素都是一个字符串,表示文件的绝对路径。 请注意,在使用该向量之前,您必须显式地清除该向量,除非您希望该函数附加到该向量。 该函数也适用于网络驱动器目录路径。
- 查看源代码中的“获取文件列表”按钮事件处理程序函数,以了解步骤 1 到 5 的操作。
- 检查“Util.cpp”源文件或下面的代码片段,以详细描述该函数如何在内部工作,其中有大量注释。
void CUtil::GetFileList(const _tstring& strTargetDirectoryPath,
const _tstring& strWildCard, bool bLookInSubdirectories,
vector<_tstring>& vecstrFileList)
{
// Check whether target directory string is empty
if(strTargetDirectoryPath.compare(_T("")) == 0)
{
return;
}
// Remove "\\" if present at the end of the target directory
// Then make a copy of it and use as the current search directory
_tstring strCurrentDirectory = RemoveDirectoryEnding(strTargetDirectoryPath);
// This data structure stores information about the file/folder
// that is found by any of these Win32 API functions:
// FindFirstFile, FindFirstFileEx, or FindNextFile function
WIN32_FIND_DATA fdDesktop = {0};
// Format and copy the current directory
// Note the addition of the wildcard *.*, which represents all files
//
// Below is a list of wildcards that you can use
// * (asterisk) - represents zero or more characters
// at the current character position
// ? (question mark) - represents a single character
//
// Modify this function so that the function can take in a search
// pattern with wildcards and use it in the line
// below to find for e.g. only *.mpg files
//
// "\\?\" prefix to the file path means that the
// file system supports large paths/filenames
_tstring strDesktopPath = _T("");
strDesktopPath += _T("\\\\?\\");
strDesktopPath += strCurrentDirectory;
strDesktopPath = AddDirectoryEnding(strDesktopPath);
if(strWildCard.compare(_T("")) == 0)
{
strDesktopPath += _T("*.*");
}
else
{
strDesktopPath += strWildCard;
}
// Finds the first file and populates the
// WIN32_FIND_DATA data structure with its information
// The return value is a search handle used in subsequent
// calls to FindNextFile or FindClose functions
HANDLE hDesktop = ::FindFirstFile(strDesktopPath.c_str(), &fdDesktop);
// If an invalid handle is returned by FindFirstFile function,
// then the directory is empty, so nothing to do but quit
if(hDesktop == INVALID_HANDLE_VALUE)
{
return;
}
// Do this on the first file found and repeat for every next
// file found until all the required files
// that match the search pattern are found
do
{
// Reconstruct the path
_tstring strPath = _T("");
strPath += strCurrentDirectory;
strPath = AddDirectoryEnding(strPath);
strPath += fdDesktop.cFileName;
// Check if a directory was found
if(fdDesktop.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Get the name of the directory
_tstring strCurrentDirectoryName = GetDirectoryName(strPath);
// If its a current (.) or previous (..)
// directory indicator, just skip it
if((strCurrentDirectoryName.compare(_T(".")) == 0) ||
(strCurrentDirectoryName.compare(_T("..")) == 0))
{
continue;
}
// Other wise this is a sub-directory
else
{
// Check whether function was called
// to include sub-directories in the search
if(bLookInSubdirectories)
{
// If sub-directories are to be searched as well,
// recursively call the function again,
// with the target directory as the sub-directory
GetFileList(strPath, strWildCard, bLookInSubdirectories,
vecstrFileList);
}
}
}
// A file was found
else
// if(fdDesktop.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
{
// Add the string to the vector
vecstrFileList.push_back(_tstring(strPath));
}
}
// Search for the next file that matches the search pattern
while(::FindNextFile(hDesktop, &fdDesktop) == TRUE);
// Close the search handle
::FindClose(hDesktop);
}
关注点
这里提供的代码用于非托管 C++;如果您使用托管代码或 C#,它使用 .NET Framework,您可以使用 Directory.GetFiles
方法;您可以在 这里 阅读相关内容。
在编写此代码时,我发现,令我恼火的是,Microsoft Windows 没有任何易于使用的非托管 C++ 代码可以以直接而简单的方式执行此操作。 如果您发现此代码有用,请发表评论,这可能会让我心情愉快
已知问题
使用通配符在子目录中递归查找文件时,如果父目录中至少没有一个此类文件,则不会搜索嵌套目录。
历史
- V1.0 - 初始版本。
- V1.1 - 修复了递归子目录搜索。