C++怎样遍历文件夹然后取得目录下的文件名?

时间:2021-11-09 14:30:54
  
   最近做个字统计的课程设计要遍历文件夹,好像这个是系统调用的问题,要用到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


该回复于2011-04-15 14:27:42被版主删除

#5


system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容

#6


  
   5 楼的高手太给力了!
  
    我最近也接触到system这个函数遍历目录,但是不知道还可以这样用!太感谢了。

   楼上的几位也感谢回答了!

   我最近准备学习win32 API然后再学习 VC,请推荐几本学习win32 API的入门书籍。

#7


应该要用到路径吧

#8


引用 5 楼 zhao4zhong1 的回复:
system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容


请问我能不能将打开的文件路径用一个字符串来表示,我是这样想的,但是不对

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是比较友好的方式。

#11


CRuntime类库好像只有个system函数
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧

#12


system 还可以这样啊  学了

#13


引用 9 楼 aiwnx 的回复:
C/C++ code

        char szCommand[MAX_PATH] = {0};
        string filedir="D:\\ubuntu\\\*.*";
        wsprintfA(szCommand, "dir /a-d /b %s >d:\\allfiles.txt", filedir.c_str());
        system(szCom……

  
  正解,虽然我不知道是什么意思,但是还是先用了再说。
  
  我想问一下学习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


该回复于2011-04-15 14:27:42被版主删除

#5


system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容

#6


  
   5 楼的高手太给力了!
  
    我最近也接触到system这个函数遍历目录,但是不知道还可以这样用!太感谢了。

   楼上的几位也感谢回答了!

   我最近准备学习win32 API然后再学习 VC,请推荐几本学习win32 API的入门书籍。

#7


应该要用到路径吧

#8


引用 5 楼 zhao4zhong1 的回复:
system("dir /a-d /b d:\\mydir\\*.* >d:\\allfiles.txt");
//然后读文件d:\\allfiles.txt的内容


请问我能不能将打开的文件路径用一个字符串来表示,我是这样想的,但是不对

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是比较友好的方式。

#11


CRuntime类库好像只有个system函数
而且还很难封装其他函数
我记得winAPI好像有
具体百度吧

#12


system 还可以这样啊  学了

#13


引用 9 楼 aiwnx 的回复:
C/C++ code

        char szCommand[MAX_PATH] = {0};
        string filedir="D:\\ubuntu\\\*.*";
        wsprintfA(szCommand, "dir /a-d /b %s >d:\\allfiles.txt", filedir.c_str());
        system(szCom……

  
  正解,虽然我不知道是什么意思,但是还是先用了再说。
  
  我想问一下学习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;
}
}