遍历文件夹:C#使用WIN32API来遍历文件和目录

  我们有时需要遍历某个目录下文件和子目录可以使用.IO.DirectoryInfo.GetDirectories或GetFiles来获得目录下所有文件和子目录当这个目录下内容比较多时这个操作就比较耗时间有时我们仅仅需要知道某个目录下是否有子目录这样操作显然是浪费时间此时我们很容易想到 3个Win32API FindFirstFileFindNextFile和FindClose这 3个API搭配使用就能遍历文件和子目录了而且可以遍历时候随时中止避免无谓操作

  C#中可以使用foreach来遍历某个序列遍历使用对象必须实现 .Collections.IEnumeable接口而内部遍历器则必须实现.Collections.IEnumerator 为了使用方便我们在使用FindFirstFile等API时封装为 IEnumerator而且实际上是有条件封装

  这里很多人就会提到C#API执行效率问题认为应当用CCAPI才是正道使用C#则有些鸡肋但在我个人编程经历中也有不少API经验发现其实效率问题不大可以省略我只是做常规运行在PC机上面软件SoftwareCPU通常超过1GHZ而且无需考虑高实时性和高效率若过于考虑效率问题会加大软件Software开发消耗从工程开发管理方面看是不合理我应当解决比较突出效率问题不突出影响不大效率问题有时间才去解决使用C#封装Win32API必然会降低执行效率但是封装后使用方便快捷综合考虑认为这是正确

  这里说下“技术镀金”这个问题所谓技术镀金就是开发人员在项目软件Software开发中过于追求技术完美性试图在技术上镀上层完美金壳导致软件Software开发工作量加大项目时间拉长有可能导致项目失败我吃过“技术镀金”苦头现在我内心是追求完美但实际开发时经常有意压制追求完美心思

  现在继续探讨封装大计本次封装重点在于实现IEnumerator,而IEnumeable只是IEnumerator个包装IEnumerator实现思路方法 Re MoveNext 和属性 CurrentRe思路方法用于重新设置遍历器MoveNext用于查找下个文件或目录而Current返回当前文件或目录

  这个遍历器还得注意FindClose必须在遍历完毕没有找到文件或子目录后若不该API则会造成内存泄漏

  根据上述设计我写出如下代码这段代码功能单希望有人能用得上

/// <summary>
/// 文件或目录遍历器,本类型为 FileDirectoryEnumerator 个包装
/// </summary>
/// <remarks>
///
/// 编写 袁永福 ( http://www.xdesigner.cn )2006-12-8
///
/// 以下代码演示使用这个文件目录遍历器
///
/// FileDirectoryEnumerable e = FileDirectoryEnumerable;
/// e.SearchPath = @"c:";
/// e.ReturnStringType = true ;
/// e.SearchPattern = "*.exe";
/// e.SearchDirectory = false ;
/// e.SearchFile = true;
/// foreach (object name in e)
/// {
///   .Console.WriteLine(name);
/// }
/// .Console.ReadLine;
///
///</remarks>
public FileDirectoryEnumerable : .Collections.IEnumerable
{
  private bool bolReturnStringType = true;
  /// <summary>
  /// 是否以串方式返回查询结果,若返回true则当前对象返回为串,
  /// 否则返回 .IO.FileInfo或.IO.DirectoryInfo类型
  /// </summary>
  public bool ReturnStringType
  {
    get { bolReturnStringType; }
     { bolReturnStringType = value; }
  }
  private strSearchPattern = "*";
  /// <summary>
  /// 文件或目录名通配符
  /// </summary>
  public SearchPattern
  {
    get { strSearchPattern; }
     { strSearchPattern = value; }
  }
  private strSearchPath = null;
  /// <summary>
  /// 搜索路径,必须为绝对路径
  /// </summary>
  public SearchPath
  {
    get { strSearchPath; }
     { strSearchPath = value; }
  }
  private bool bolSearchForFile = true;
  /// <summary>
  /// 是否查找文件
  /// </summary>
  public bool SearchForFile
  {
    get { bolSearchForFile; }
     { bolSearchForFile = value; }
  }
  private bool bolSearchForDirectory = true;
  /// <summary>
  /// 是否查找子目录
  /// </summary>
  public bool SearchForDirectory
  {
    get { bolSearchForDirectory; }
     { bolSearchForDirectory = value; }
  }
  private bool bolThrowIOException = true;
  /// <summary>
  /// 发生IO时是否抛出异常
  /// </summary>
  public bool ThrowIOException
  {
    get { this.bolThrowIOException; }
     { this.bolThrowIOException = value; }
  }
  /// <summary>
  /// 返回内置文件和目录遍历器
  /// </summary>
  /// <s>遍历器对象</s>
  public .Collections.IEnumerator GetEnumerator
  {
    FileDirectoryEnumerator e = FileDirectoryEnumerator;
    e.ReturnStringType = this.bolReturnStringType;
    e.SearchForDirectory = this.bolSearchForDirectory;
    e.SearchForFile = this.bolSearchForFile;
    e.SearchPath = this.strSearchPath;
    e.SearchPattern = this.strSearchPattern;
    e.ThrowIOException = this.bolThrowIOException;
    myList.Add(e);
     e;
  }
  /// <summary>
  /// 关闭对象
  /// </summary>
  public void Close
  {
    foreach (FileDirectoryEnumerator e in myList)
    {
      e.Close;
    }
    myList.Clear;
  }
  private .Collections.ArrayList myList = .Collections.ArrayList;
}//public FileDirectoryEnumerable : .Collections.IEnumerable
/// <summary>
/// 文件和目录遍历器
/// </summary>
/// <remarks>本对象为Win32API FindFirstFile , FindNextFile
/// 和 FindClose 个包装
///
/// 以下代码演示使用了 FileDirectoryEnumerator
///
/// FileDirectoryEnumerator e = FileDirectoryEnumerator;
/// e.SearchPath = @"c:";
/// e.Re;
/// e.ReturnStringType = true ;
/// while (e.MoveNext)
/// {
///   .Console.WriteLine
///     ( e.LastAccessTime.("yyyy-MM-dd HH:mm:ss")
///     + "  " + e.FileLength + " t" + e.Name );
/// }
/// e.Close;
/// .Console.ReadLine;
///
/// 编写 袁永福 ( http://www.xdesigner.cn )2006-12-8</remarks>
public FileDirectoryEnumerator : .Collections.IEnumerator
{


  #region 表示对象当前状态数据和属性 **********************************

  /// <summary>
  /// 当前对象
  /// </summary>
  private object objCurrentObject = null;
  private bool bolIsEmpty = false;
  /// <summary>
  /// 该目录为空
  /// </summary>
  public bool IsEmpty
  {
    get { bolIsEmpty; }
  }
  private SearchedCount = 0;
  /// <summary>
  /// 已找到对象个数
  /// </summary>
  public SearchedCount
  {
    get { SearchedCount; }
  }
  private bool bolIsFile = true;
  /// <summary>
  /// 当前对象是否为文件,若为true则当前对象为文件,否则为目录
  /// </summary>
  public bool IsFile
  {
    get { bolIsFile; }
  }
  private LastErrorCode = 0;
  /// <summary>
  /// 最后次操作Win32代码
  /// </summary>
  public LastErrorCode
  {
    get { LastErrorCode; }
  }
  /// <summary>
  /// 当前对象名称
  /// </summary>
  public Name
  {
    get
    {
       (this.objCurrentObject != null)
      {
         (objCurrentObject is )
           ()this.objCurrentObject;
        
           ((.IO.FileInfo)this.objCurrentObject).Name;
      }
       null;
    }
  }
  /// <summary>
  /// 当前对象属性
  /// </summary>
  public .IO.FileAttributes Attributes
  {
    get { (.IO.FileAttributes)myData.dwFileAttributes; }
  }
  /// <summary>
  /// 当前对象创建时间
  /// </summary>
  public .DateTime CreationTime
  {
    get
    {
      long time = ToLong(myData.ftCreationTime_dwHighDateTime, myData.ftCreationTime_dwLowDateTime);
      .DateTime dtm = .DateTime.FromFileTimeUtc(time);
       dtm.ToLocalTime;
    }
  }
  /// <summary>
  /// 当前对象最后访问时间
  /// </summary>
  public .DateTime LastAccessTime
  {
    get
    {
      long time = ToLong(myData.ftLastAccessTime_dwHighDateTime, myData.ftLastAccessTime_dwLowDateTime);
      .DateTime dtm = .DateTime.FromFileTimeUtc(time);
       dtm.ToLocalTime;
    }
  }
  /// <summary>
  /// 当前对象最后保存时间
  /// </summary>
  public .DateTime LastWriteTime
  {
    get
    {
      long time = ToLong(myData.ftLastWriteTime_dwHighDateTime, myData.ftLastWriteTime_dwLowDateTime);
      .DateTime dtm = .DateTime.FromFileTimeUtc(time);
       dtm.ToLocalTime;
    }
  }
  /// <summary>
  /// 当前文件长度,若为当前对象为文件则返回文件长度,若当前对象为目录则返回0
  /// </summary>
  public long FileLength
  {
    get
    {
       (this.bolIsFile)
         ToLong(myData.nFileSizeHigh, myData.nFileSizeLow);
      
         0;
    }
  }


  #endregion

  #region 控制对象特性些属性 ****************************************

  private bool bolThrowIOException = true;
  /// <summary>
  /// 发生IO时是否抛出异常
  /// </summary>
  public bool ThrowIOException
  {
    get { this.bolThrowIOException; }
     { this.bolThrowIOException = value; }
  }
  private bool bolReturnStringType = true;
  /// <summary>
  /// 是否以串方式返回查询结果,若返回true则当前对象返回为串,
  /// 否则返回 .IO.FileInfo或.IO.DirectoryInfo类型
  /// </summary>
  public bool ReturnStringType
  {
    get { bolReturnStringType; }
     { bolReturnStringType = value; }
  }
  private strSearchPattern = "*";
  /// <summary>
  /// 要匹配文件或目录名,支持通配符
  /// </summary>
  public SearchPattern
  {
    get { strSearchPattern; }
     { strSearchPattern = value; }
  }
  private strSearchPath = null;
  /// <summary>
  /// 搜索父目录,必须为绝对路径,不得有通配符,该目录必须存在
  /// </summary>
  public SearchPath
  {
    get { strSearchPath; }
     { strSearchPath = value; }
  }
  private bool bolSearchForFile = true;
  /// <summary>
  /// 是否查找文件
  /// </summary>
  public bool SearchForFile
  {
    get { bolSearchForFile; }
     { bolSearchForFile = value; }
  }
  private bool bolSearchForDirectory = true;
  /// <summary>
  /// 是否查找子目录
  /// </summary>
  public bool SearchForDirectory
  {
    get { bolSearchForDirectory; }
     { bolSearchForDirectory = value; }
  }
  #endregion
  /// <summary>
  /// 关闭对象,停止搜索
  /// </summary>
  public void Close
  {
    this.CloseHandler;
  }
  #region IEnumerator 成员 **********************************************
  /// <summary>
  /// 返回当前对象
  /// </summary>
  public object Current
  {
    get { objCurrentObject ; }
  }
  /// <summary>
  /// 找到下个文件或目录
  /// </summary>
  /// <s>操作是否成功</s>
  public bool MoveNext
  {
    bool success = false;
    while (true)
    {
       (this.bolStartSearchFlag)
        success = this.SearchNext;
      
        success = this.StartSearch;
       (success)
      {
         (this.UpdateCurrentObject)
           true;
      }
      
      {
        this.objCurrentObject = null;
         false;
      }
    }
  }
  /// <summary>
  /// 重新设置对象
  /// </summary>
  public void Re
  {
     (this.strSearchPath null)
      throw .ArgumentNullException("SearchPath can not null");
     (this.strSearchPattern null || this.strSearchPattern.Length 0)
      this.strSearchPattern = "*";
    this.SearchedCount = 0;
    this.objCurrentObject = null;
    this.CloseHandler;
    this.bolStartSearchFlag = false;
    this.bolIsEmpty = false;
    this.LastErrorCode = 0;
  }


  #endregion

  #region 声明WIN32API以及结构 **************************************

  [Serializable,
  .Runtime.InteropServices.StructLayout
    (.Runtime.InteropServices.LayoutKind.Sequential,
    CharSet = .Runtime.InteropServices.CharSet.Auto
    ),
  .Runtime.InteropServices.BestFitMapping(false)]
  private struct WIN32_FIND_DATA
  {
    public dwFileAttributes;
    public ftCreationTime_dwLowDateTime;
    public ftCreationTime_dwHighDateTime;
    public ftLastAccessTime_dwLowDateTime;
    public ftLastAccessTime_dwHighDateTime;
    public ftLastWriteTime_dwLowDateTime;
    public ftLastWriteTime_dwHighDateTime;
    public nFileSizeHigh;
    public nFileSizeLow;
    public dwReserved0;
    public dwReserved1;
    [.Runtime.InteropServices.MarshalAs
      (.Runtime.InteropServices.UnmanagedType.ByValTStr,
      SizeConst = 260)]
    public cFileName;
    [.Runtime.InteropServices.MarshalAs
      (.Runtime.InteropServices.UnmanagedType.ByValTStr,
      SizeConst = 14)]
    public cAlternateFileName;
  }
  [.Runtime.InteropServices.DllImport
    ("kernel32.dll",
    CharSet = .Runtime.InteropServices.CharSet.Auto,
    SetLastError = true)]
  private extern IntPtr FindFirstFile( pFileName, ref WIN32_FIND_DATA pFindFileData);
  [.Runtime.InteropServices.DllImport
    ("kernel32.dll",
    CharSet = .Runtime.InteropServices.CharSet.Auto,
    SetLastError = true)]
  private extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData);
  [.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
  private extern bool FindClose(IntPtr hndFindFile);
  private long ToLong( height , low)
  {
    long v = ( u ) height ;
    v = v << 0x20;
    v = v | ( ( u )low );
     v;
  }
  private void WinIOError( errorCode, str)
  {
    switch (errorCode)
    {
       80:
        throw .IO.IOException("IO_FileExists :" + str);
       0x57:
        throw .IO.IOException("IOError:" + MakeHRFromErrorCode(errorCode));
       0xce:
        throw .IO.PathTooLongException("PathTooLong:" + str );
       2:
        throw .IO.FileNotFoundException("FileNotFound:" + str);
       3:
        throw .IO.DirectoryNotFoundException("PathNotFound:" + str);
       5:
        throw UnauthorizedAccessException("UnauthorizedAccess:" + str);
       0x20:
        throw .IO.IOException("IO_SharingViolation:" + str);
    }
    throw .IO.IOException("IOError:" + MakeHRFromErrorCode(errorCode));
  }
  private MakeHRFromErrorCode( errorCode)
  {
     (-2147024896 | errorCode);
  }


  #endregion

  #region 内部代码群 ****************************************************

  private readonly IntPtr INVALID_HANDLE_VALUE = IntPtr(-1);
  /// <summary>
  /// 查找处理底层句柄
  /// </summary>
  private .IntPtr SearchHandler = INVALID_HANDLE_VALUE;
  private WIN32_FIND_DATA myData = WIN32_FIND_DATA;
  /// <summary>
  /// 开始搜索标志
  /// </summary>
  private bool bolStartSearchFlag = false;
  /// <summary>
  /// 关闭内部句柄
  /// </summary>
  private void CloseHandler
  {
     (this.SearchHandler != INVALID_HANDLE_VALUE)
    {
      FindClose(this.SearchHandler);
      this.SearchHandler = INVALID_HANDLE_VALUE;
    }
  }
  /// <summary>
  /// 开始搜索
  /// </summary>
  /// <s>操作是否成功</s>
  private bool StartSearch
  {
    bolStartSearchFlag = true;
    bolIsEmpty = false;
    objCurrentObject = null;
    LastErrorCode = 0;
     strPath = .IO.Path.Combine(strSearchPath, this.strSearchPattern);
    this.CloseHandler;
    SearchHandler = FindFirstFile(strPath, ref myData);
     (SearchHandler INVALID_HANDLE_VALUE)
    {
      LastErrorCode = .Runtime.InteropServices.Marshal.GetLastWin32Error;
       (LastErrorCode 2)
      {
        bolIsEmpty = true;
         false;
      }
      ( this.bolThrowIOException )
        WinIOError( LastErrorCode , strSearchPath);
      
         false;
    }
     true;
  }
  /// <summary>
  /// 搜索下
  /// </summary>
  /// <s>操作是否成功</s>
  private bool SearchNext
  {
     (bolStartSearchFlag false)
       false;
     (bolIsEmpty)
       false;
     (SearchHandler INVALID_HANDLE_VALUE)
       false;
    LastErrorCode = 0 ;
     (FindNextFile(SearchHandler, ref myData) false)
    {
      LastErrorCode = .Runtime.InteropServices.Marshal.GetLastWin32Error;
      this.CloseHandler;
       (LastErrorCode != 0 && LastErrorCode != 0x12)
      {
         (this.bolThrowIOException)
          WinIOError(LastErrorCode , strSearchPath);
        
           false;
      }
       false;
    }
     true;
  }//private bool SearchNext
  /// <summary>
  /// 更新当前对象
  /// </summary>
  /// <s>操作是否成功</s>
  private bool UpdateCurrentObject
  {
     (SearchHandler INVALID_HANDLE_VALUE)
       false;
    bool Result = false;
    this.objCurrentObject = null;
     ((myData.dwFileAttributes & 0x10) 0)
    {
      // 当前对象为文件
      this.bolIsFile = true;
       (this.bolSearchForFile)
        Result = true;
    }
    
    {
      // 当前对象为目录
      this.bolIsFile = false;
       (this.bolSearchForDirectory)
      {
         (myData.cFileName "." || myData.cFileName "..")
          Result = false;
        
          Result = true;
      }
    }
     (Result)
    {
       (this.bolReturnStringType)
        this.objCurrentObject = myData.cFileName;
      
      {
         p = .IO.Path.Combine(this.strSearchPath, myData.cFileName);
         (this.bolIsFile)
        {
          this.objCurrentObject = .IO.FileInfo(p);
        }
        
        {
          this.objCurrentObject = .IO.DirectoryInfo(p);
        }
      }
      this.SearchedCount;
    }
     Result;
  }//private bool UpdateCurrentObject
  #endregion
}//public FileDirectoryEnumerator : .Collections.IEnumerator




  http://www.cnblogs.com/xdesigner/archive/2006/12/08/586177.html



Tags:  java遍历文件夹 遍历文件 vc遍历文件 遍历文件夹

延伸阅读

最新评论

发表评论