最近做个字统计的课程设计要遍历文件夹,好像这个是系统调用的问题,要用到API,纯C++实现不了?
我没有学习WIN32 API不懂的怎样遍历文件夹,在网上看了很多帖子还是云里雾
里的,希望各位能够给个代码(最好用函数方式吧,方便我直接调用了)。
如果有详细的注释就更好了,这样我看起来也懂些。 谢谢大家了。
17 个解决方案
#1
c++也是用api,底层都是api,findfirst,findnext
#2
摘自MSDN...
#include <Windows.h>
#include <stdio.h>
#include <malloc.h>
#include <tchar.h>
#include <wchar.h>
#include <strsafe.h>
#define BUFSIZE MAX_PATH
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError;
LPTSTR DirSpec;
size_t length_of_arg;
INT retval;
DirSpec = (LPTSTR) malloc (BUFSIZE);
if( DirSpec == NULL )
{
printf( "Insufficient memory available\n" );
retval = 1;
goto Cleanup;
}
// Check for the directory to query, specified as
// a command-line parameter; otherwise, print usage.
if(argc != 2)
{
_tprintf(TEXT("Usage: Test <dir>\n"));
retval = 2;
goto Cleanup;
}
// Check that the input is not larger than allowed.
StringCbLength(argv[1], BUFSIZE, &length_of_arg);
if (length_of_arg > (BUFSIZE - 2))
{
_tprintf(TEXT("Input directory is too large.\n"));
retval = 3;
goto Cleanup;
}
_tprintf (TEXT("Target directory is %s.\n"), argv[1]);
// Prepare string for use with FindFile functions. First,
// copy the string to a buffer, then append '\*' to the
// directory name.
StringCbCopyN (DirSpec, BUFSIZE, argv[1], length_of_arg+1);
StringCbCatN (DirSpec, BUFSIZE, TEXT("\\*"), 2*sizeof(TCHAR));
// Find the first file in the directory.
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
_tprintf (TEXT("Invalid file handle. Error is %u.\n"),
GetLastError());
retval = (-1);
}
else
{
_tprintf (TEXT("First file name is: %s\n"),
FindFileData.cFileName);
// List all the other files in the directory.
while (FindNextFile(hFind, &FindFileData) != 0)
{
_tprintf (TEXT("Next file name is: %s\n"),
FindFileData.cFileName);
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
_tprintf (TEXT("FindNextFile error. Error is %u.\n"),
dwError);
retval = (-1);
goto Cleanup;
}
}
retval = 0;
Cleanup:
free(DirSpec);
return retval;
}
#3
void ParserDirectory(char* strDirName)
{
CFileFind tempFind;
char strTempFileFind[MAX_PATH];
sprintf(strTempFileFind,"%s\\*.*", strDirName);
BOOL IsFinded = tempFind.FindFile(strTempFileFind);
while (IsFinded)
{
IsFinded = tempFind.FindNextFile();
if (!tempFind.IsDots())
{
char strFoundFileName[MAX_PATH];
strcpy(strFoundFileName, tempFind.GetFileName().GetBuffer(MAX_PATH));
if (tempFind.IsDirectory())
{
char strTempDir[MAX_PATH];
sprintf(strTempDir,"%s\\%s", strDirName, strFoundFileName);
ParserDirectory(strTempDir);
}
else
{
//找到一个文件,strFoundFileName为文件名
//在此添加处理
}
}
}
tempFind.Close();
}
#4
#5
system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容
//然后读文件d:\\allfiles.txt的内容
#6
5 楼的高手太给力了!
我最近也接触到system这个函数遍历目录,但是不知道还可以这样用!太感谢了。
楼上的几位也感谢回答了!
我最近准备学习win32 API然后再学习 VC,请推荐几本学习win32 API的入门书籍。
#7
应该要用到路径吧
#8
请问我能不能将打开的文件路径用一个字符串来表示,我是这样想的,但是不对
string filedir="D:\\\\mydir\\\\*.txt";
system("dir /a-d /b filedir.c_str() >d:\\allfiles.txt");
这样system找不到指定文件,
我想用一个string来接受一个键盘输入当作要遍历的路径,请问怎么解决?
#9
char szCommand[MAX_PATH] = {0};
string filedir="D:\\ubuntu\\\*.*";
wsprintfA(szCommand, "dir /a-d /b %s >d:\\allfiles.txt", filedir.c_str());
system(szCommand);
#10
不太推荐你用system,因为遍历文件夹需要递归很多目录,那样会创建并删除大量临时文件,速度会慢好几倍,而且显得程序代码很笨拙。
CFileFind是比较友好的方式。
CFileFind是比较友好的方式。
#11
CRuntime类库好像只有个system函数
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧
#12
system 还可以这样啊 学了
#13
正解,虽然我不知道是什么意思,但是还是先用了再说。
我想问一下学习VC之前是不是最好先学win32 api和MFC啊?
#14
用boost filesystem啊,很方便的,编译文件,删除创建。。。还是portable得
#15
// TortoiseSVN - a Windows shell extension for easy version control
// Copyright (C) 2005 - 2006, 2010 - TortoiseSVN
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#pragma once
#include <string>
/**
* \ingroup Utils
* Enumerates over a directory tree, non-recursively.
* Advantages over CFileFind:
* 1) Return values are not broken. An error return from
* CFileFind::FindNext() indicates that the *next*
* call to CFileFind::FindNext() will fail.
* A failure from CSimpleFileFind means *that* call
* failed, which is what I'd expect.
* 2) Error handling. If you use CFileFind, you are
* required to call ::GetLastError() yourself, there
* is no abstraction.
* 3) Support for ignoring the "." and ".." directories
* automatically.
* 4) No dynamic memory allocation.
*/
class CSimpleFileFind {
private:
/**
* Windows FindFirstFile() handle.
*/
HANDLE m_hFindFile;
/**
* Windows error code - if all is well, ERROR_SUCCESS.
* At end of directory, ERROR_NO_MORE_FILES.
*/
DWORD m_dError;
/**
* Flag indicating that FindNextFile() has not yet been
* called.
*/
BOOL m_bFirst;
protected:
/**
* The prefix for files in this directory.
* Ends with a "\", unless it's a drive letter only
* ("C:" is different from "C:\", and "C:filename" is
* legal anyway.)
*/
std::string m_sPathPrefix;
/**
* The file data returned by FindFirstFile()/FindNextFile().
*/
WIN32_FIND_DATA m_FindFileData;
public:
/**
* Constructor.
*
* \param sPath The path to search in.
* \param sPattern The filename pattern - default all files.
*/
CSimpleFileFind(const std::string &sPath, LPCTSTR pPattern = _T("*.*"));
~CSimpleFileFind();
/**
* Advance to the next file.
* Note that the state of this object is undefined until
* this method is called the first time.
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory (use IsError() and IsPastEnd() to
* disambiguate).
*/
BOOL FindNextFile();
/**
* Advance to the next file, ignoring the "." and ".."
* pseudo-directories (if seen).
*
* Behaves like FindNextFile(), apart from ignoring "."
* and "..".
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory.
*/
BOOL FindNextFileNoDots();
/**
* Advance to the next file, ignoring all directories.
*
* Behaves like FindNextFile(), apart from ignoring
* directories.
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory.
*/
BOOL FindNextFileNoDirectories();
/**
* Get the Windows error code.
* Only useful when IsError() returns true.
*
* \return Windows error code.
*/
inline DWORD GetError() const
{
return m_dError;
}
/**
* Check if the current file data is valid.
* (I.e. there has not been an error and we are not past
* the end of the directory).
*
* \return TRUE iff the current file data is valid.
*/
inline BOOL IsValid() const
{
return (m_dError == ERROR_SUCCESS);
}
/**
* Check if we have passed the end of the directory.
*
* \return TRUE iff we have passed the end of the directory.
*/
inline BOOL IsPastEnd() const
{
return (m_dError == ERROR_NO_MORE_FILES);
}
/**
* Check if there has been an unexpected error - i.e.
* any error other than passing the end of the directory.
*
* \return TRUE iff there has been an unexpected error.
*/
inline BOOL IsError() const
{
return (m_dError != ERROR_SUCCESS)
&& (m_dError != ERROR_NO_MORE_FILES);
}
/**
* Check if the current file is a directory.
*
* \return TRUE iff the current file is a directory.
*/
inline bool IsDirectory() const
{
return !!(m_FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
/**
* Get the current file name (excluding the path).
*
* \return the current file name.
*/
inline std::string GetFileName() const
{
return std::string(m_FindFileData.cFileName);
}
/*
* Get the current file name, including the path.
*
* \return the current file path.
*/
inline std::string GetFilePath() const
{
return m_sPathPrefix + m_FindFileData.cFileName;
}
/**
* Check if the current file is the "." or ".."
* pseudo-directory.
*
* \return TRUE iff the current file is the "." or ".."
* pseudo-directory.
*/
inline BOOL IsDots() const
{
return IsDirectory()
&& m_FindFileData.cFileName[0] == _T('.')
&& ( (m_FindFileData.cFileName[1] == 0)
|| (m_FindFileData.cFileName[1] == _T('.')
&& m_FindFileData.cFileName[2] == 0) );
}
};
/**
* \ingroup Utils
* Enumerates over a directory tree, recursively.
*
* \par requirements
* win95 or later
* winNT4 or later
* MFC
*
* \version 1.0
* first version
*
* \date 18-Feb-2004
*
* \author Jon Foster
*
* \par license
* This code is GPL'd.
*/
class CDirFileEnum
{
private:
class CDirStackEntry : public CSimpleFileFind {
public:
CDirStackEntry(CDirStackEntry * seNext, const std::string& sDirName);
~CDirStackEntry();
CDirStackEntry * m_seNext;
};
CDirStackEntry * m_seStack;
BOOL m_bIsNew;
inline void PopStack();
inline void PushStack(const std::string& sDirName);
public:
/**
* Iterate through the specified directory and all subdirectories.
* It does not matter whether or not the specified directory ends
* with a slash. Both relative and absolute paths are allowed,
* the results of this iterator will be consistent with the style
* passed to this constructor.
*
* @param dirName The directory to search in.
*/
CDirFileEnum(const std::string& dirName);
/**
* Destructor. Frees all resources.
*/
~CDirFileEnum();
/**
* Get the next file from this iterator.
*
* \param result On successful return, holds the full path to the found
* file. (If this function returns FALSE, the value of
* result is unspecified).
* \param pbIsDirectory Pointer to a bool variable which will hold
* TRUE if the \c result path is a directory, FALSE
* if it's a file. Pass NULL if you don't need that information.
* \param bRecurse if the last result was a directory, specifies whether to
* recurse into that directory or skip it.
* \return TRUE iff a file was found, false at end of the iteration.
*/
BOOL NextFile(std::string &result, bool* pbIsDirectory, bool bRecurse = true);
};
#16
// TortoiseSVN - a Windows shell extension for easy version control
// Copyright (C) 2005-2006, 2009-2010 - TortoiseSVN
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#include <Windows.h>
#include <tchar.h>
#include "DirFileEnum.h"
using namespace std;
CSimpleFileFind::CSimpleFileFind(const string &sPath, LPCTSTR pPattern) :
m_dError(ERROR_SUCCESS),
m_bFirst(TRUE),
m_sPathPrefix(sPath)
{
// Add a trailing \ to m_sPathPrefix if it is missing.
// Do not add one to "C:" since "C:" and "C:\" are different.
int len = m_sPathPrefix.length();
if (len != 0)
{
TCHAR ch = sPath[len-1];
if (ch != '\\' && (ch != ':' || len != 2))
{
m_sPathPrefix += "\\";
}
}
if ((len >= 248)&&(m_sPathPrefix.substr(0, 4).compare(_T("\\\\?\\")))) {
string filename = _T("\\\\?\\") + m_sPathPrefix + pPattern;
m_hFindFile = ::FindFirstFile(filename.c_str(), &m_FindFileData);
}
else {
string filename = m_sPathPrefix + pPattern;
m_hFindFile = ::FindFirstFile(filename.c_str(), &m_FindFileData);
}
if (m_hFindFile == INVALID_HANDLE_VALUE) {
m_dError = ::GetLastError();
}
}
CSimpleFileFind::~CSimpleFileFind()
{
if (m_hFindFile != INVALID_HANDLE_VALUE) {
::FindClose(m_hFindFile);
}
}
BOOL CSimpleFileFind::FindNextFile()
{
if (m_dError) {
return FALSE;
}
if (m_bFirst) {
m_bFirst = FALSE;
return TRUE;
}
if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {
m_dError = ::GetLastError();
return FALSE;
}
return TRUE;
}
BOOL CSimpleFileFind::FindNextFileNoDots()
{
BOOL result;
do {
result = FindNextFile();
} while (result && IsDots());
return result;
}
BOOL CSimpleFileFind::FindNextFileNoDirectories()
{
BOOL result;
do {
result = FindNextFile();
} while (result && IsDirectory());
return result;
}
/*
* Implementation notes:
*
* This is a depth-first traversal. Directories are visited before
* their contents.
*
* We keep a stack of directories. The deepest directory is at the top
* of the stack, the originally-requested directory is at the bottom.
* If we come across a directory, we first return it to the user, then
* recurse into it. The finder at the bottom of the stack always points
* to the file or directory last returned to the user (except immediately
* after creation, when the finder points to the first valid thing we need
* to return, but we haven't actually returned anything yet - hence the
* m_bIsNew variable).
*
* Errors reading a directory are assumed to be end-of-directory, and
* are otherwise ignored.
*
* The "." and ".." psedo-directories are ignored for obvious reasons.
*/
CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,
const string& sDirName)
: CSimpleFileFind(sDirName),
m_seNext(seNext)
{
}
CDirFileEnum::CDirStackEntry::~CDirStackEntry()
{
}
inline void CDirFileEnum::PopStack()
{
CDirStackEntry * seToDelete = m_seStack;
m_seStack = seToDelete->m_seNext;
delete seToDelete;
}
inline void CDirFileEnum::PushStack(const string& sDirName)
{
m_seStack = new CDirStackEntry(m_seStack,sDirName);
}
CDirFileEnum::CDirFileEnum(const string& sDirName) :
m_seStack(NULL),
m_bIsNew(TRUE)
{
PushStack(sDirName);
}
CDirFileEnum::~CDirFileEnum()
{
while (m_seStack != NULL) {
PopStack();
}
}
BOOL CDirFileEnum::NextFile(string &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
{
if (m_bIsNew) {
// Special-case first time - haven't found anything yet,
// so don't do recurse-into-directory check.
m_bIsNew = FALSE;
} else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
PushStack(m_seStack->GetFilePath());
}
while (m_seStack && !m_seStack->FindNextFileNoDots()) {
// No more files in this directory, try parent.
PopStack();
}
if (m_seStack)
{
sResult = m_seStack->GetFilePath();
if(pbIsDirectory != NULL)
{
*pbIsDirectory = m_seStack->IsDirectory();
}
return TRUE;
} else {
return FALSE;
}
}
#17
#include <iostream>
#include <string>
using namespace std;
#include <Windows.h>
#include <tchar.h>
#include <algorithm>
#include "DirFileEnum.h"
int main()
{
// 列举d:\\下所有文件夹和文件
CDirFileEnum dirEnum("D:\\");
string file;
bool isDir; // 是否是文件夹
while (dirEnum.NextFile(file, &isDir, true)) {
if (isDir)
cout << "文件夹" << file << endl;
else
cout << "文件" << file << endl;
}
}
#1
c++也是用api,底层都是api,findfirst,findnext
#2
摘自MSDN...
#include <Windows.h>
#include <stdio.h>
#include <malloc.h>
#include <tchar.h>
#include <wchar.h>
#include <strsafe.h>
#define BUFSIZE MAX_PATH
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError;
LPTSTR DirSpec;
size_t length_of_arg;
INT retval;
DirSpec = (LPTSTR) malloc (BUFSIZE);
if( DirSpec == NULL )
{
printf( "Insufficient memory available\n" );
retval = 1;
goto Cleanup;
}
// Check for the directory to query, specified as
// a command-line parameter; otherwise, print usage.
if(argc != 2)
{
_tprintf(TEXT("Usage: Test <dir>\n"));
retval = 2;
goto Cleanup;
}
// Check that the input is not larger than allowed.
StringCbLength(argv[1], BUFSIZE, &length_of_arg);
if (length_of_arg > (BUFSIZE - 2))
{
_tprintf(TEXT("Input directory is too large.\n"));
retval = 3;
goto Cleanup;
}
_tprintf (TEXT("Target directory is %s.\n"), argv[1]);
// Prepare string for use with FindFile functions. First,
// copy the string to a buffer, then append '\*' to the
// directory name.
StringCbCopyN (DirSpec, BUFSIZE, argv[1], length_of_arg+1);
StringCbCatN (DirSpec, BUFSIZE, TEXT("\\*"), 2*sizeof(TCHAR));
// Find the first file in the directory.
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
_tprintf (TEXT("Invalid file handle. Error is %u.\n"),
GetLastError());
retval = (-1);
}
else
{
_tprintf (TEXT("First file name is: %s\n"),
FindFileData.cFileName);
// List all the other files in the directory.
while (FindNextFile(hFind, &FindFileData) != 0)
{
_tprintf (TEXT("Next file name is: %s\n"),
FindFileData.cFileName);
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
_tprintf (TEXT("FindNextFile error. Error is %u.\n"),
dwError);
retval = (-1);
goto Cleanup;
}
}
retval = 0;
Cleanup:
free(DirSpec);
return retval;
}
#3
void ParserDirectory(char* strDirName)
{
CFileFind tempFind;
char strTempFileFind[MAX_PATH];
sprintf(strTempFileFind,"%s\\*.*", strDirName);
BOOL IsFinded = tempFind.FindFile(strTempFileFind);
while (IsFinded)
{
IsFinded = tempFind.FindNextFile();
if (!tempFind.IsDots())
{
char strFoundFileName[MAX_PATH];
strcpy(strFoundFileName, tempFind.GetFileName().GetBuffer(MAX_PATH));
if (tempFind.IsDirectory())
{
char strTempDir[MAX_PATH];
sprintf(strTempDir,"%s\\%s", strDirName, strFoundFileName);
ParserDirectory(strTempDir);
}
else
{
//找到一个文件,strFoundFileName为文件名
//在此添加处理
}
}
}
tempFind.Close();
}
#4
#5
system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容
//然后读文件d:\\allfiles.txt的内容
#6
5 楼的高手太给力了!
我最近也接触到system这个函数遍历目录,但是不知道还可以这样用!太感谢了。
楼上的几位也感谢回答了!
我最近准备学习win32 API然后再学习 VC,请推荐几本学习win32 API的入门书籍。
#7
应该要用到路径吧
#8
请问我能不能将打开的文件路径用一个字符串来表示,我是这样想的,但是不对
string filedir="D:\\\\mydir\\\\*.txt";
system("dir /a-d /b filedir.c_str() >d:\\allfiles.txt");
这样system找不到指定文件,
我想用一个string来接受一个键盘输入当作要遍历的路径,请问怎么解决?
#9
char szCommand[MAX_PATH] = {0};
string filedir="D:\\ubuntu\\\*.*";
wsprintfA(szCommand, "dir /a-d /b %s >d:\\allfiles.txt", filedir.c_str());
system(szCommand);
#10
不太推荐你用system,因为遍历文件夹需要递归很多目录,那样会创建并删除大量临时文件,速度会慢好几倍,而且显得程序代码很笨拙。
CFileFind是比较友好的方式。
CFileFind是比较友好的方式。
#11
CRuntime类库好像只有个system函数
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧
#12
system 还可以这样啊 学了
#13
正解,虽然我不知道是什么意思,但是还是先用了再说。
我想问一下学习VC之前是不是最好先学win32 api和MFC啊?
#14
用boost filesystem啊,很方便的,编译文件,删除创建。。。还是portable得
#15
// TortoiseSVN - a Windows shell extension for easy version control
// Copyright (C) 2005 - 2006, 2010 - TortoiseSVN
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#pragma once
#include <string>
/**
* \ingroup Utils
* Enumerates over a directory tree, non-recursively.
* Advantages over CFileFind:
* 1) Return values are not broken. An error return from
* CFileFind::FindNext() indicates that the *next*
* call to CFileFind::FindNext() will fail.
* A failure from CSimpleFileFind means *that* call
* failed, which is what I'd expect.
* 2) Error handling. If you use CFileFind, you are
* required to call ::GetLastError() yourself, there
* is no abstraction.
* 3) Support for ignoring the "." and ".." directories
* automatically.
* 4) No dynamic memory allocation.
*/
class CSimpleFileFind {
private:
/**
* Windows FindFirstFile() handle.
*/
HANDLE m_hFindFile;
/**
* Windows error code - if all is well, ERROR_SUCCESS.
* At end of directory, ERROR_NO_MORE_FILES.
*/
DWORD m_dError;
/**
* Flag indicating that FindNextFile() has not yet been
* called.
*/
BOOL m_bFirst;
protected:
/**
* The prefix for files in this directory.
* Ends with a "\", unless it's a drive letter only
* ("C:" is different from "C:\", and "C:filename" is
* legal anyway.)
*/
std::string m_sPathPrefix;
/**
* The file data returned by FindFirstFile()/FindNextFile().
*/
WIN32_FIND_DATA m_FindFileData;
public:
/**
* Constructor.
*
* \param sPath The path to search in.
* \param sPattern The filename pattern - default all files.
*/
CSimpleFileFind(const std::string &sPath, LPCTSTR pPattern = _T("*.*"));
~CSimpleFileFind();
/**
* Advance to the next file.
* Note that the state of this object is undefined until
* this method is called the first time.
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory (use IsError() and IsPastEnd() to
* disambiguate).
*/
BOOL FindNextFile();
/**
* Advance to the next file, ignoring the "." and ".."
* pseudo-directories (if seen).
*
* Behaves like FindNextFile(), apart from ignoring "."
* and "..".
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory.
*/
BOOL FindNextFileNoDots();
/**
* Advance to the next file, ignoring all directories.
*
* Behaves like FindNextFile(), apart from ignoring
* directories.
*
* \return TRUE if a file was found, FALSE on error or
* end-of-directory.
*/
BOOL FindNextFileNoDirectories();
/**
* Get the Windows error code.
* Only useful when IsError() returns true.
*
* \return Windows error code.
*/
inline DWORD GetError() const
{
return m_dError;
}
/**
* Check if the current file data is valid.
* (I.e. there has not been an error and we are not past
* the end of the directory).
*
* \return TRUE iff the current file data is valid.
*/
inline BOOL IsValid() const
{
return (m_dError == ERROR_SUCCESS);
}
/**
* Check if we have passed the end of the directory.
*
* \return TRUE iff we have passed the end of the directory.
*/
inline BOOL IsPastEnd() const
{
return (m_dError == ERROR_NO_MORE_FILES);
}
/**
* Check if there has been an unexpected error - i.e.
* any error other than passing the end of the directory.
*
* \return TRUE iff there has been an unexpected error.
*/
inline BOOL IsError() const
{
return (m_dError != ERROR_SUCCESS)
&& (m_dError != ERROR_NO_MORE_FILES);
}
/**
* Check if the current file is a directory.
*
* \return TRUE iff the current file is a directory.
*/
inline bool IsDirectory() const
{
return !!(m_FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
/**
* Get the current file name (excluding the path).
*
* \return the current file name.
*/
inline std::string GetFileName() const
{
return std::string(m_FindFileData.cFileName);
}
/*
* Get the current file name, including the path.
*
* \return the current file path.
*/
inline std::string GetFilePath() const
{
return m_sPathPrefix + m_FindFileData.cFileName;
}
/**
* Check if the current file is the "." or ".."
* pseudo-directory.
*
* \return TRUE iff the current file is the "." or ".."
* pseudo-directory.
*/
inline BOOL IsDots() const
{
return IsDirectory()
&& m_FindFileData.cFileName[0] == _T('.')
&& ( (m_FindFileData.cFileName[1] == 0)
|| (m_FindFileData.cFileName[1] == _T('.')
&& m_FindFileData.cFileName[2] == 0) );
}
};
/**
* \ingroup Utils
* Enumerates over a directory tree, recursively.
*
* \par requirements
* win95 or later
* winNT4 or later
* MFC
*
* \version 1.0
* first version
*
* \date 18-Feb-2004
*
* \author Jon Foster
*
* \par license
* This code is GPL'd.
*/
class CDirFileEnum
{
private:
class CDirStackEntry : public CSimpleFileFind {
public:
CDirStackEntry(CDirStackEntry * seNext, const std::string& sDirName);
~CDirStackEntry();
CDirStackEntry * m_seNext;
};
CDirStackEntry * m_seStack;
BOOL m_bIsNew;
inline void PopStack();
inline void PushStack(const std::string& sDirName);
public:
/**
* Iterate through the specified directory and all subdirectories.
* It does not matter whether or not the specified directory ends
* with a slash. Both relative and absolute paths are allowed,
* the results of this iterator will be consistent with the style
* passed to this constructor.
*
* @param dirName The directory to search in.
*/
CDirFileEnum(const std::string& dirName);
/**
* Destructor. Frees all resources.
*/
~CDirFileEnum();
/**
* Get the next file from this iterator.
*
* \param result On successful return, holds the full path to the found
* file. (If this function returns FALSE, the value of
* result is unspecified).
* \param pbIsDirectory Pointer to a bool variable which will hold
* TRUE if the \c result path is a directory, FALSE
* if it's a file. Pass NULL if you don't need that information.
* \param bRecurse if the last result was a directory, specifies whether to
* recurse into that directory or skip it.
* \return TRUE iff a file was found, false at end of the iteration.
*/
BOOL NextFile(std::string &result, bool* pbIsDirectory, bool bRecurse = true);
};
#16
// TortoiseSVN - a Windows shell extension for easy version control
// Copyright (C) 2005-2006, 2009-2010 - TortoiseSVN
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#include <Windows.h>
#include <tchar.h>
#include "DirFileEnum.h"
using namespace std;
CSimpleFileFind::CSimpleFileFind(const string &sPath, LPCTSTR pPattern) :
m_dError(ERROR_SUCCESS),
m_bFirst(TRUE),
m_sPathPrefix(sPath)
{
// Add a trailing \ to m_sPathPrefix if it is missing.
// Do not add one to "C:" since "C:" and "C:\" are different.
int len = m_sPathPrefix.length();
if (len != 0)
{
TCHAR ch = sPath[len-1];
if (ch != '\\' && (ch != ':' || len != 2))
{
m_sPathPrefix += "\\";
}
}
if ((len >= 248)&&(m_sPathPrefix.substr(0, 4).compare(_T("\\\\?\\")))) {
string filename = _T("\\\\?\\") + m_sPathPrefix + pPattern;
m_hFindFile = ::FindFirstFile(filename.c_str(), &m_FindFileData);
}
else {
string filename = m_sPathPrefix + pPattern;
m_hFindFile = ::FindFirstFile(filename.c_str(), &m_FindFileData);
}
if (m_hFindFile == INVALID_HANDLE_VALUE) {
m_dError = ::GetLastError();
}
}
CSimpleFileFind::~CSimpleFileFind()
{
if (m_hFindFile != INVALID_HANDLE_VALUE) {
::FindClose(m_hFindFile);
}
}
BOOL CSimpleFileFind::FindNextFile()
{
if (m_dError) {
return FALSE;
}
if (m_bFirst) {
m_bFirst = FALSE;
return TRUE;
}
if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {
m_dError = ::GetLastError();
return FALSE;
}
return TRUE;
}
BOOL CSimpleFileFind::FindNextFileNoDots()
{
BOOL result;
do {
result = FindNextFile();
} while (result && IsDots());
return result;
}
BOOL CSimpleFileFind::FindNextFileNoDirectories()
{
BOOL result;
do {
result = FindNextFile();
} while (result && IsDirectory());
return result;
}
/*
* Implementation notes:
*
* This is a depth-first traversal. Directories are visited before
* their contents.
*
* We keep a stack of directories. The deepest directory is at the top
* of the stack, the originally-requested directory is at the bottom.
* If we come across a directory, we first return it to the user, then
* recurse into it. The finder at the bottom of the stack always points
* to the file or directory last returned to the user (except immediately
* after creation, when the finder points to the first valid thing we need
* to return, but we haven't actually returned anything yet - hence the
* m_bIsNew variable).
*
* Errors reading a directory are assumed to be end-of-directory, and
* are otherwise ignored.
*
* The "." and ".." psedo-directories are ignored for obvious reasons.
*/
CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,
const string& sDirName)
: CSimpleFileFind(sDirName),
m_seNext(seNext)
{
}
CDirFileEnum::CDirStackEntry::~CDirStackEntry()
{
}
inline void CDirFileEnum::PopStack()
{
CDirStackEntry * seToDelete = m_seStack;
m_seStack = seToDelete->m_seNext;
delete seToDelete;
}
inline void CDirFileEnum::PushStack(const string& sDirName)
{
m_seStack = new CDirStackEntry(m_seStack,sDirName);
}
CDirFileEnum::CDirFileEnum(const string& sDirName) :
m_seStack(NULL),
m_bIsNew(TRUE)
{
PushStack(sDirName);
}
CDirFileEnum::~CDirFileEnum()
{
while (m_seStack != NULL) {
PopStack();
}
}
BOOL CDirFileEnum::NextFile(string &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
{
if (m_bIsNew) {
// Special-case first time - haven't found anything yet,
// so don't do recurse-into-directory check.
m_bIsNew = FALSE;
} else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
PushStack(m_seStack->GetFilePath());
}
while (m_seStack && !m_seStack->FindNextFileNoDots()) {
// No more files in this directory, try parent.
PopStack();
}
if (m_seStack)
{
sResult = m_seStack->GetFilePath();
if(pbIsDirectory != NULL)
{
*pbIsDirectory = m_seStack->IsDirectory();
}
return TRUE;
} else {
return FALSE;
}
}
#17
#include <iostream>
#include <string>
using namespace std;
#include <Windows.h>
#include <tchar.h>
#include <algorithm>
#include "DirFileEnum.h"
int main()
{
// 列举d:\\下所有文件夹和文件
CDirFileEnum dirEnum("D:\\");
string file;
bool isDir; // 是否是文件夹
while (dirEnum.NextFile(file, &isDir, true)) {
if (isDir)
cout << "文件夹" << file << endl;
else
cout << "文件" << file << endl;
}
}