【C++源代码】文件夹比较、文件比较的数据结构,定义和实现

原创 2006年06月21日 15:12:00

说明:本来昨天我想找个程序同步一下自己的PC和笔记本上的数据文件夹,当然这方面的应用程序里面老大应该是Beyond Compare,可惜下载一个,发现又注册,连试用都不让,于是干脆自己花了三个钟头写了一个,提供出来,如果大家有好的建议,不妨告诉我;如果谁正在写这方面的程序,可以参考一下:),还有就是我本来是打算模仿Beyond Compare做个封装的CListCtrl扩展类,后来一动手发现要做UI而且要做得比较好看还是要花点力气的,所以偶就偷懒了一下,如果哪位兄弟愿意实现,可以在我的基础上直接实现下去就是了。

另外,正好昨天把Martin Fowler<Refactor>英文版读完了一遍,顺便把里面那些理论用到这个小Demo程序来了:)
这是我第一次把源代码放到CSDN论坛上,希望如果版主觉得好,可以提倡一下大家都提供一点自己的心得(有版权的除外),呵呵,这样下次大家搜索的话直接可以有现成的代码用了
========================================================================
思路:
文件夹比较,无非是一个递归比较过程:同名的文件夹,递归比较;同名的文件,比较大小(我使用了位比较,可能比较慢,不过可以通过设置比较函数地址来加入你自己的比较函数);不同名的文件,就要单独加入了。

定义:
定义了4个类,CFldCmpFileNodeCFldCmpFileTreeCFldCmpNodeCFldCmpTree
分别是两个树。
CFldCmpFileTree
:这个类用于分析指定的文件夹,将其中的文件信息等都填入。CFldCmpFileNode是这个树的节点类。这两个类对用户而已是隐藏的。
CFldCmpTree
:是包含比较结果的类,这个类对用户是公开的。

详细设计:
两个树的类都采用了链表结构,Tree中包含了所有根节点(CFldCmpNode)的信息,然后由这些节点分别维护它们自己的子节点。同时,每个节点都有一个指向父节点的指针。

关键问题:
1.
文件比较:前面已经说了,类CFldCmpTree支持自定义的比较文件(只限文件之间的比较函数),我提供的默认比较函数使用了位比较(具体的实现是使用了STL里面的bitset,另外一个MFC版本就是直接用CStringCompare比较,可以使用宏_NOT_USE_STL来控制编译STL版本还是MFC版本的比较函数。
2.
文件夹Tree的构成:为了便于比较,我没有使用ID+Array的格式定义树,而使用链表来实现是为了能够比较方面的进行递归比较。具体的方法就是递归的比较树的同层的节点。

调用方式:
简单的代码如下:
 CFldCmpTree tree;
 tree.ParseFolder(szLeftPath, szRightPath);

文件:
FldCmpStruct.h
FldCmpStruct.cpp

使用方法:这个,不用我说了吧,呵呵,加入你自己的工程就可以了

 

头文件
//
// File : FldCmpStruct.h
// Written by Alva Chien, 2003.3.24
// ======================================================================
// Note:
// To avoid hard code mission, I have change some classes members into 
// public property, so, you need fix this (ah, a hard work) before you put
// this file into a security using.
//////////////////////////////////////////////////////////////////////////

#ifndef _H_FLDCMP_STRUCT_
#define _H_FLDCMP_STRUCT_

// User bitset to compare file
#include <bitset>
#include <string>
#include <fstream>
#include <strstream>
using namespace std;

// Include <afxtempl.h> or not
#if !defined(__AFXTEMPL_H__)
  #include  <afxtempl.h>
#endif // !__AFXTEMPL_H__

// Using ACLib  or not
#if !defined(AC_C_COMMON_H_)
# define _NOUSE_ACLIB_
# pragma message("Complied without using ACLib.dll...")
#endif // !AC_C_COMMON_H_

//////////////////////////////////////////////////////////////////////////
// Macro definiton( avoid link to ACLib.dll )
#ifdef _NOUSE_ACLIB_
#define FCS_SAFEDEL(p) if (p != NULL) /
{ /
  delete p; /
  p = NULL; /
}

inline DWORD FCS_GetFileSize(LPCTSTR lpszFile)
{
  ASSERT(lpszFile != NULL);
  if (lpszFile == NULL)
    return 0;

#ifdef _NOT_USE_STL
  DWORD dwSize = 0;
  HANDLE hFile; 
 
  hFile = CreateFile(lpszFile, // create 
    GENERIC_READ,    // open for writing 
    0,       // do not share 
    NULL,      // no security 
    OPEN_EXISTING,    // existing file only 
    FILE_ATTRIBUTE_NORMAL,  // normal file 
    NULL);      // no attr. template 
 
  if (hFile != INVALID_HANDLE_VALUE) 
  { 
    dwSize = GetFileSize(hFile, NULL); 
    if (dwSize == INVALID_FILE_SIZE) 
      dwSize = 0;

    CloseHandle(hFile);
  }
  return dwSize;
#else
  ifstream in(lpszFile);
  ASSERT(in != NULL);
  in.seekg(0, ios::end);
  streampos pos = in.tellg();
  return (DWORD)pos; 
#endif // _NOT_USE_STL
}
#endif // _NOUSE_ACLIB_

//////////////////////////////////////////////////////////////////////////
// Declarations

// Folder compare function
typedef int (*PFNFCCMPFUNC)(LPARAM, LPARAM, LPARAM);

class CFldCmpFileNode;
class CFldCmpNode;
typedef CFldCmpFileNode *CFldCmpFileNodePtr;
typedef CFldCmpNode *CFldCmpNodePtr;
typedef CTypedPtrArray<CPtrArray, CFldCmpFileNodePtr> CFldCmpFileNodePtrArray;
typedef CTypedPtrArray<CPtrArray, CFldCmpNodePtr> CFldCmpNodePtrArray;

// Compare item type
typedef enum
{
  FCT_MATCH,  // Match
  FCT_LNEW,  // Left newer
  FCT_RNEW,  // Right newer
  FCT_LORPHAN, // Left is orphane
 
 FCT_RORPHAN  // Right is orpane
}
FldCmpType;

//////////////////////////////////////////////////////////////////////////
// class CFldCmpFileNode
class CFldCmpFileNode
{
// Constructor
public:
  CFldCmpFileNode();
  virtual ~CFldCmpFileNode();
// ===========================================================================
// Note :
// If you use the Copy Constructor or operator '=' to assign the Node, it may
// leads the memory, for it not release the children.
// In fact, I strongly suggest use the CFldCmpFileTree instead of build a 
// tree manualy.
// ===========================================================================
  CFldCmpFileNode(const CFldCmpFileNode &fn);
  CFldCmpFileNode &operator =(const CFldCmpFileNode &fn);

// Operation
public:
  // Clean data
  void CleanData();
  // Get family nodes
  UINT GetFamilyNodeNumber() const;

// Members
public
:
 // File item
  CString  m_strName;
  BOOL  m_bFolder;
  COleDateTime m_dtModified;
  DWORD  m_dwSize;

 // Used to build the tree
 
CFldCmpFileNode *m_pFather;
  CFldCmpFileNodePtrArray m_arChildPtrs;
  UINT  m_nLevel;

 // No used
  DWORD  m_dwData;
};

//////////////////////////////////////////////////////////////////////////
// class CFldCmpFileTree
class CFldCmpFileTree
{
// Constructor
public:
  CFldCmpFileTree();
  virtual ~CFldCmpFileTree();

// Opertion
public:
  // Parse folder
 
 BOOL ParseFolder(
    LPCTSTR lpszPath, 
    CFldCmpFileNodePtr pFa = NULL, 
    UINT nLevel = 0
   );
  // Clean data
  void CleanData();
  // Get node number
  UINT GetNodeNumber() const;
  // Get root array
  const CFldCmpFileNodePtrArray &GetRootArray() const {  return m_arRootPtrs; }

#ifdef _DEBUG
  // Display tree info
  void DisplayDebugInfo(CFldCmpFileNodePtr pFather = NULL);
#endif // _DEBUG
 
// Members
protected:
  // Root item array
 
 CFldCmpFileNodePtrArray m_arRootPtrs;
};

//////////////////////////////////////////////////////////////////////////
// class CFldCmpNode

class
 CFldCmpNode
{
// Constructor
public:
  CFldCmpNode();
  virtual ~CFldCmpNode();
  CFldCmpNode(const CFldCmpNode &cn);
  CFldCmpNode &operator =(const CFldCmpNode &cn);

// Operation
public:
  // Clean data
  void CleanData();
  // Get family nodes
  UINT GetFamilyNodeNumber() const;
  // Compare two node, used for sort
  int Compare(const CFldCmpNode &nc) const;

// Members
public:
  FldCmpType  m_type;   // Type
  CString   m_strName;  // Name
  COleDateTime m_dtLeft;  // Left last modified time
  COleDateTime m_dtRight;  // Right last modified time
  DWORD   m_dwLeftSize; // Left file size
  DWORD   m_dwRightSize; // Right file size
  BOOL   m_bFolder;  // Folder or not

  // Used to build the tree
  CFldCmpNodePtr m_pFather;   // Pointer of father node
  CFldCmpNodePtrArray m_arChildPtrs; // Children node pointer array
  UINT   m_nLevel;   // Level, from the root

  // No used
  DWORD   m_dwData;
};

//////////////////////////////////////////////////////////////////////////
// class CFldCmpTree
class CFldCmpTree
{
// Constrcution
public:
  CFldCmpTree();
  virtual ~CFldCmpTree();

// Interface
public
:
  // Clean data
  void CleanData();
#ifdef _DEBUG
  // Display tree info
  void DisplayDebugInfo(CFldCmpNodePtr pFather = NULL);
#endif // _DEBUG
  // Get node number
  UINT GetNodeNumber() const;
  // Combine file tree
  BOOL ParseFolder(
    LPCTSTR lpszLeft,
    LPCTSTR lpszRight
   );
  // Get root array
 const CFldCmpNodePtrArray &GetRootArray() const {  return m_arRootPtrs; }
  // Sort 
  void Sort();
  // Compare function 
 
void SetCustomSortFunc(PFNFCCMPFUNC);
  // Get node full path
  CString GetNodeFullPath(
    const CFldCmpNodePtr pNode,
    BOOL bLeft = TRUE
   ) const;

// Operations
protected:
  // Combine file tree
  BOOL CombineFileTrees(
    const CFldCmpFileTree &treeLeft,
    const CFldCmpFileTree &treeRight
   );
  // Copy left file tree
  BOOL CopyLeftFileTree(
    const CFldCmpFileNodePtrArray &arNodePtrs,
    CFldCmpNodePtr pFather = NULL
   );
  // Combine right file tree
  BOOL CombineRightTree(
    const CFldCmpFileNodePtrArray &arFileNodePtrs,
    CFldCmpNodePtr pFather = NULL
   );
  // Sort function
 
 void SortArray(  CFldCmpNodePtrArray &arArray  );

// Members
protected:
  // Root item array
  CFldCmpNodePtrArray m_arRootPtrs;
  // File's compare function
  PFNFCCMPFUNC m_pFnFileCmp;
  // Left path
  CString m_strLeftPath;
  // Right path
  CString m_strRightPath;
};

#endif // _H_FLDCMP_STRUCT_

 

实现文件上半部分:
 //
// File: FldCmpStruct.cpp
// Written by Alva Chien, 2004.3.24
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FldCmpStruct.h"
//////////////////////////////////////////////////////////////////////////
// Default file compare function
// Support a default compare function
int FCS_DefaultFileCmp(
  LPARAM lpNode,
  LPARAM lpszLeftFile,
  LPARAM lpszRightFile
 )

  ASSERT((lpNode != NULL) && (lpszLeftFile != NULL) && (lpszRightFile != NULL));
  if((lpNode == NULL) || (lpszLeftFile == NULL) || (lpszRightFile == NULL))
    return FALSE;
 
  CFldCmpNodePtr pNode = (CFldCmpNodePtr)lpNode;
  if (pNode->m_bFolder) // Folder ? 
    return 0;

  DWORD dwSizeLeft = pNode->m_dwLeftSize, dwSizeRight = pNode->m_dwRightSize;

  int nRst = 0;
  BOOL bContinue = FALSE;
  if (dwSizeLeft == dwSizeRight)
  {
#if !defined(_NOT_USE_STL)
    // Read the file content
   ifstream inLeft((LPCTSTR)lpszLeftFile);
   ifstream inRight((LPCTSTR)lpszRightFile);
   ASSERT((inLeft != NULL) && (inRight != NULL));
   strstream strleft, strright;
   strleft<<inLeft.rdbuf();
   strright<<inRight.rdbuf();
   inLeft.close();
   inRight.close();

    // In 32 bits computers, sizeof(byte) == 8, so 256 * 8 => 2048
   char *pLeft = strleft.str();
   char *pRight = strright.str();
   int nTime = dwSizeLeft / 256;
   if (dwSizeLeft % 256 )      nTime += 1;

   // Hard work again, 55555555....
   for(int i = 0; i < nTime; i ++)
   {
     if ( (i != nTime -1) || ( (i == nTime -1) && (dwSizeLeft % 256 == 0)) )
     {
       bitset<2048> bsLeft(pLeft + i * 2048, 2048);
       bitset<2048> bsRight(pRight + i * 2048, 2048);
       int nCount = bsLeft.count();
       bsLeft &= bsRight;
       if (nCount != bsLeft.count())
       {
         // Not same! out!
         bContinue = TRUE;
         break;
      }
    }
    else
    {
      bitset<2048> bsLeft(pLeft + i *2048);
      bitset<2048> bsRight(pRight + i * 2048);
      int nCount = bsLeft.count();
      bsLeft &= bsRight;
      if (nCount != bsLeft.count())
      {
        // Not same! out!
        bContinue = TRUE;
        break;
       }
     }
   }

   delete strleft.str();
   delete strright.str();
#else
   LPBYTE pLeft = new BYTE[dwSizeLeft];
   LPBYTE pRight = new BYTE[dwSizeLeft];
   ASSERT((pLeft != NULL) && (pRight != NULL));

   CFile fileLeft, fileRight;
   if (fileLeft.Open((LPCTSTR)lpszLeftFile, CFile::modeRead))
   {
     fileLeft.ReadHuge(pLeft, dwSizeLeft);
     fileLeft.Close();
   }
   if (fileRight.Open((LPCTSTR)lpszRightFile, CFile::modeRead))
   {
     fileRight.ReadHuge(pRight, dwSizeLeft);
     fileRight.Close();
   }
  
   if (CString(pLeft).Compare(CString(pRight)) == 0)
     bContinue = FALSE;
  
   delete [] pLeft;
   pLeft = NULL;
   delete [] pRight;
   pRight = NULL;
#endif // !_NOT_USE_STL
  
    if (!bContinue)    return 0;
  }
 
  // No same, compare it by the time
  if(pNode->m_dtLeft > pNode->m_dtRight)     nRst = 1;
  else if (pNode->m_dtLeft < pNode->m_dtRight)    nRst = -1;
  else nRst = 0;

  return nRst;
}

//////////////////////////////////////////////////////////////////////////
// class CFldCmpFileNode

// Constructor
CFldCmpFileNode::CFldCmpFileNode()
{
  m_strName = _T("");
  m_bFolder = FALSE;
  m_dtModified = COleDateTime::GetCurrentTime();
  m_dwSize = 0;

  // Used to build the tree
  m_pFather = NULL;
  m_arChildPtrs.SetSize(0);
  m_nLevel = (UINT)-1;

  // Used for arrange
  m_dwData = 0;
}

// Decomstructor
CFldCmpFileNode::~CFldCmpFileNode() { CleanData(); }

// Copy constructor
CFldCmpFileNode::CFldCmpFileNode(const CFldCmpFileNode &fn) {   *this = fn; }

// Override operator =
CFldCmpFileNode &CFldCmpFileNode::operator =(const CFldCmpFileNode &fn)
{
  if ( this != &fn)
  {
    m_strName = fn.m_strName;
    m_bFolder = fn.m_bFolder;
    m_dtModified = fn.m_dtModified;
    m_dwSize = fn.m_dwSize;

    // Used to build the tree
    m_pFather = fn.m_pFather;
    m_arChildPtrs.RemoveAll();
    m_arChildPtrs.Copy(fn.m_arChildPtrs);
    m_nLevel = fn.m_nLevel;

    // Used for arrange
    m_dwData = fn.m_dwData;
  }

  return *this;
}

// Clean data
void CFldCmpFileNode::CleanData()
{
  for(int i = 0; i < m_arChildPtrs.GetSize(); i++)
  {
    CFldCmpFileNodePtr pNode = m_arChildPtrs.GetAt(i);
    ASSERT(pNode != NULL);
    pNode->CleanData();
#ifdef _NOUSE_ACLIB_
    FCS_SAFEDEL(pNode);
#else 
    ACC_SAFEDEL(pNode);
#endif // _NOUSE_ACLIB_
 }

  m_arChildPtrs.RemoveAll();
}

// Get node family number
UINT CFldCmpFileNode::GetFamilyNodeNumber() const
{
  UINT nCount = 0;
  for(int i = 0; i < m_arChildPtrs.GetSize(); i ++)
    nCount += m_arChildPtrs.GetAt(i)->GetFamilyNodeNumber();
 
  nCount += 1; // Himself
  return nCount;
}

//////////////////////////////////////////////////////////////////////////
// class CFldCmpFileTree

// Constructor
CFldCmpFileTree::CFldCmpFileTree() { m_arRootPtrs.SetSize(0);}

// Decomstructor
CFldCmpFileTree::~CFldCmpFileTree() { CleanData();}

// Get node number
UINT CFldCmpFileTree::GetNodeNumber() const
{
  UINT nCount = 0;
  for(int i = 0; i < m_arRootPtrs.GetSize(); i++)
    nCount += m_arRootPtrs.GetAt(i)->GetFamilyNodeNumber();

  return nCount;
}

// Parse folder
BOOL CFldCmpFileTree::ParseFolder(
  LPCTSTR lpszPath, 
  CFldCmpFileNodePtr pFa, 
  UINT nLevel
 )
{
  ASSERT(lpszPath != NULL);
  if(lpszPath == NULL)    return FALSE;

  CString str = lpszPath;
  if (str.IsEmpty())   return FALSE;
 
  str.TrimRight();
  str.TrimRight(_T('//'));
  str += _T("//*.*");
 
  // start working for files
 
 CFileFind finder;
  BOOL bWorking = finder.FindFile(str);
  while (bWorking)
  {
     bWorking = finder.FindNextFile();
  
     if (finder.IsDots())    continue;
  
     WIN32_FILE_ATTRIBUTE_DATA fad;
     CFldCmpFileNodePtr pNode = new CFldCmpFileNode;
     ASSERT(pNode != NULL);
     if (pNode == NULL)   return FALSE;

     pNode->m_strName = finder.GetFileName();
     pNode->m_nLevel = nLevel;
     pNode->m_pFather = pFa;

     if (finder.IsDirectory())
     {
        pNode->m_bFolder = TRUE;
   
       // Add it into the array   
       if (pFa == NULL)    m_arRootPtrs.Add(pNode);
      else    pFa->m_arChildPtrs.Add(pNode);
   
       // Recursiving...
      if (!ParseFolder(
        finder.GetFilePath(),
        pNode,
        nLevel + 1))
         return FALSE;
     }
     else
     {
        pNode->m_bFolder = FALSE;
   
        if (GetFileAttributesEx(finder.GetFilePath(), GetFileExInfoStandard, &fad) != FALSE)
        {
            pNode->m_dtModified = (COleDateTime)fad.ftLastWriteTime;
#ifdef _NOUSE_ACLIB_
           pNode->m_dwSize = FCS_GetFileSize(finder.GetFilePath());
#else
           pNode->m_dwSize = ACC_GetFileSize(finder.GetFilePath());
#endif // _NOUSE_ACLIB_
     }
   
      // Add it
     if (pFa == NULL)    m_arRootPtrs.Add(pNode);
     else    pFa->m_arChildPtrs.Add(pNode);
     }  
  }

  return TRUE;
}

// Clean data
void CFldCmpFileTree::CleanData()
{
  for(int i = 0; i < m_arRootPtrs.GetSize(); i++)
  {
    CFldCmpFileNodePtr pNode = m_arRootPtrs.GetAt(i);
    ASSERT(pNode != NULL);
    pNode->CleanData();
#ifdef _NOUSE_ACLIB_
    FCS_SAFEDEL(pNode);
#else
    ACC_SAFEDEL(pNode);
#endif // _NOUSE_ACLIB_
  }

  m_arRootPtrs.RemoveAll();
}

#ifdef _DEBUG
// Display debug info
void CFldCmpFileTree::DisplayDebugInfo(CFldCmpFileNodePtr pFather)
{
  CFldCmpFileNodePtrArray &rNods = (pFather == NULL)? m_arRootPtrs : pFather->m_arChildPtrs;
  forint i = 0; i < rNods.GetSize(); i ++)
    DisplayDebugInfo(rNods.GetAt(i));
 
  // Then clean itselft
  if(pFather != NULL)
  {
    TRACE("Tree Level %d: %s, %s, Father %s, Size %d, Children number %d/n",
       pFather->m_nLevel, 
       pFather->m_strName,
       pFather->m_bFolder? _T("Folder") : _T("File"),
        (pFather->m_pFather == NULL) ? _T("None") : pFather->m_pFather->m_strName,
       pFather->m_dwSize,
       pFather->m_arChildPtrs.GetSize()
      );
   }
}
#endif // _DEBUG

 

实现文件中间部分
//////////////////////////////////////////////////////////////////////////
// class CFldCmpNode

// Constructor
CFldCmpNode::CFldCmpNode()
{
  m_type = FCT_MATCH;   // Type
  m_strName = _T("");   // Name
  m_dtLeft = COleDateTime::GetCurrentTime();  // Left last modified time
 
 m_dtRight = COleDateTime::GetCurrentTime();  // Right last modified time
  m_dwLeftSize = 0;   // Left file size
  m_dwRightSize = 0;   // Right file size
  m_bFolder = FALSE;   // Folder or not

  // Used to build the tree
  m_pFather = NULL;   // Pointer of father node
  m_arChildPtrs.SetSize(0); // Children node pointer array
  m_nLevel = (UINT)-1;   // Level, from the root

  // Used data
  m_dwData = 0;
}

CFldCmpNode::~CFldCmpNode() {  CleanData(); }

CFldCmpNode::CFldCmpNode(const CFldCmpNode &cn)  {  *this = cn; }

CFldCmpNode&CFldCmpNode::operator =(const CFldCmpNode &cn)
{
  if ( this != &cn)
  {
    m_type = cn.m_type;     // Type
    m_strName = cn.m_strName;   // Name
    m_dtLeft = cn.m_dtLeft;    // Left last modified time
    m_dtRight = cn.m_dtRight;   // Right last modified time
    m_dwLeftSize = cn.m_dwLeftSize;  // Left file size
    m_dwRightSize = cn.m_dwRightSize; // Right file size
    m_bFolder = cn.m_bFolder;   // Folder or not

    // Used to build the tree
 
  m_pFather = cn.m_pFather;   // Pointer of father node
    m_arChildPtrs.RemoveAll();
    m_arChildPtrs.Copy(cn.m_arChildPtrs);
    m_nLevel = cn.m_nLevel;    // Level, from the root

    // Used for arrange
    m_dwData = cn.m_dwData;
  }

  return *this;
}

// Clean data
void CFldCmpNode::CleanData()
{
  for(int i = 0; i < m_arChildPtrs.GetSize(); i++)
  {
    CFldCmpNodePtr pNode = m_arChildPtrs.GetAt(i);
    ASSERT(pNode != NULL);
    pNode->CleanData();
#ifdef _NOUSE_ACLIB_
    FCS_SAFEDEL(pNode);
#else
    ACC_SAFEDEL(pNode);
#endif // _NOUSE_ACLIB_
 }

  m_arChildPtrs.RemoveAll();
}

// Get family nodes
UINT CFldCmpNode::GetFamilyNodeNumber() const
{
  UINT nCount = 0;
  for(int i = 0; i < m_arChildPtrs.GetSize(); i ++)
    nCount += m_arChildPtrs.GetAt(i)->GetFamilyNodeNumber();
 
  nCount += 1; // Himself
  return nCount;
}

// Compare
int CFldCmpNode::Compare(const CFldCmpNode &nc) const
{
  int nRst = 0;
  if (m_bFolder && (!nc.m_bFolder))  nRst = -1;
  else if((!m_bFolder) && (nc.m_bFolder))  nRst = 1;
  else  {  nRst = lstrcmpi(m_strName, nc.m_strName); }

  return nRst;
}

//////////////////////////////////////////////////////////////////////////
// class CFldCmpTree

// Constructor
CFldCmpTree::CFldCmpTree()
{
  m_arRootPtrs.SetSize(0);
  m_pFnFileCmp = FCS_DefaultFileCmp;
}

// Deconstructor
CFldCmpTree::~CFldCmpTree() {  CleanData(); }

// Clean data
void CFldCmpTree::CleanData()
{
  for(int i = 0; i < m_arRootPtrs.GetSize(); i++)
  {
    CFldCmpNodePtr pNode = m_arRootPtrs.GetAt(i);
    ASSERT(pNode != NULL);
    pNode->CleanData();
#ifdef _NOUSE_ACLIB_
    FCS_SAFEDEL(pNode);
#else
    ACC_SAFEDEL(pNode);
#endif // _NOUSE_ACLIB_
  }

  m_arRootPtrs.RemoveAll();
}

#ifdef _DEBUG
// Display tree info
void CFldCmpTree::DisplayDebugInfo(CFldCmpNodePtr pFather)
{
  CFldCmpNodePtrArray &rNods = (pFather == NULL)?m_arRootPtrs : pFather->m_arChildPtrs;
 
  // Then clean itselft
  if(pFather != NULL)
  {
     TRACE("Tree Level %d: %s, %s, Father %s, Left Size %d, Right Size %d, Children number %d/n",
       pFather->m_nLevel, 
       pFather->m_strName,
       pFather->m_bFolder? _T("Folder") : _T("File"),
       (pFather->m_pFather == NULL) ? _T("None") : pFather->m_pFather->m_strName,
       pFather->m_dwLeftSize,
       pFather->m_dwRightSize,
       pFather->m_arChildPtrs.GetSize()
      );
   }
  forint i = 0; i < rNods.GetSize(); i ++)
    DisplayDebugInfo(rNods.GetAt(i));
}
#endif // _DEBUG

// Copy left file tree
BOOL CFldCmpTree::CopyLeftFileTree(
  const CFldCmpFileNodePtrArray &arNodePtrs,
  CFldCmpNodePtr pFather
 )
{
  int nSize = arNodePtrs.GetSize();

  int i = 0;
  for(; i < nSize; i ++)
  {
    // Add it
    CFldCmpFileNodePtr pFile = arNodePtrs.GetAt(i);
    CFldCmpNodePtr pNode = new CFldCmpNode;
    ASSERT(pNode != NULL);
    if (pNode == NULL)
    {
     CleanData();
     return FALSE;
    }
    pNode->m_strName = pFile->m_strName;
    pNode->m_bFolder = pFile->m_bFolder;
    pNode->m_dtLeft = pFile->m_dtModified;
    pNode->m_dwLeftSize = pFile->m_dwSize;
    pNode->m_nLevel = pFile->m_nLevel;
    pNode->m_pFather = pFather;
    pNode->m_type = FCT_LORPHAN;
    if(pFather != NULL)
      pFather->m_arChildPtrs.Add(pNode);
    else
      m_arRootPtrs.Add(pNode);

    // Add it's children
    CopyLeftFileTree(pFile->m_arChildPtrs, pNode);
  } 

   return TRUE;
}

// Get node number
UINT CFldCmpTree::GetNodeNumber() const
{
  UINT nCount = 0;
  for(int i = 0; i < m_arRootPtrs.GetSize(); i++)
    nCount += m_arRootPtrs.GetAt(i)->GetFamilyNodeNumber();

  return nCount;
}

 

// Combine the right tree
BOOL CFldCmpTree::CombineRightTree(
  const CFldCmpFileNodePtrArray &arFileNodePtrs, 
  CFldCmpNodePtr pFather
  )
{
  CFldCmpNodePtrArray &arNodes = (pFather == NULL) ? m_arRootPtrs 
    : pFather->m_arChildPtrs;
  BOOL bExist = FALSE;
  int i = 0;
  int nArSize = arNodes.GetSize();
 
  for(; i < arFileNodePtrs.GetSize(); i ++)
  {
    // Process each element
    CFldCmpFileNodePtr pFileNode = arFileNodePtrs.GetAt(i);
    CFldCmpNodePtr pNode = NULL;

    bExist = FALSE;
    int j = 0;

    for(; j < nArSize; j ++)
    {   
       if (arNodes.GetAt(j)->m_strName == pFileNode->m_strName)
       {
         bExist = TRUE;
         break;
      }
   }

   if (bExist)
   {
     // Set the info
     pNode = arNodes.ElementAt(j);
     pNode->m_dtRight = pFileNode->m_dtModified;
     pNode->m_dwRightSize = pFileNode->m_dwSize;
     CString strLeft = GetNodeFullPath(pNode);
     CString strRight = GetNodeFullPath(pNode, FALSE);
     ASSERT(m_pFnFileCmp != NULL);
     int nRst = (m_pFnFileCmp)((LPARAM)pNode, 
        (LPARAM)(LPCTSTR)strLeft,
        (LPARAM)(LPCTSTR)strRight);   
     if(nRst == 0)
        pNode->m_type = FCT_MATCH;
     else if (nRst > 0 )
        pNode->m_type = FCT_LNEW;
     else
       pNode->m_type = FCT_RNEW;   
   }
   else
   {
     pNode = new CFldCmpNode;
     ASSERT(pNode != NULL);
     pNode->m_type = FCT_RORPHAN;
     pNode->m_dtRight = pFileNode->m_dtModified;
     pNode->m_dwRightSize = pFileNode->m_dwSize;
     pNode->m_nLevel = pFileNode->m_nLevel;
     pNode->m_strName = pFileNode->m_strName;
     pNode->m_bFolder = pFileNode->m_bFolder;
     pNode->m_pFather = pFather;   
     arNodes.Add(pNode);   
   }

    // The children pointers
    CombineRightTree(pFileNode->m_arChildPtrs, pNode);
  }

  return TRUE;
}

// Combine the file tree
BOOL CFldCmpTree::CombineFileTrees(
   const CFldCmpFileTree &treeLeft, 
   const CFldCmpFileTree &treeRight
   )
{
  CleanData();

  // First: Copy the left
  CopyLeftFileTree(treeLeft.GetRootArray());

  // Trace info
  TRACE0("/nAfter copy left file tree... ===================================/n");
  TRACE("/tTotal number is %d... ======================/n/n", GetNodeNumber());
  DisplayDebugInfo();
  TRACE0("/n");

  // Second: Combine the right tree
  CombineRightTree(treeRight.GetRootArray());
  // Trace info
  TRACE0("/nAfter combine right file tree... ===================================/n");
  TRACE("/tTotal number is %d... ======================/n/n", GetNodeNumber());
  DisplayDebugInfo();
  TRACE0("/n");

  return TRUE;
}

// Sort the array
void CFldCmpTree::SortArray(
  CFldCmpNodePtrArray &arArray
  )

  int nSize = arArray.GetSize();
  int i = 0;

  // Sort it
  for(; i < nSize; i ++)
  {
    for(int j = i + 1; j < nSize; j ++)
    {   
      CFldCmpNodePtr pNode1 = arArray.ElementAt(i);
      CFldCmpNodePtr pNode2 = arArray.ElementAt(j);
      if (pNode1->Compare(*pNode2) > 0)
      {
        // Exchange
        CFldCmpNode node;
        node = *pNode1;
        *pNode1 = *pNode2;
        *pNode2 = node;
        node.m_arChildPtrs.RemoveAll();
      }
    }
  }

  // Recursive sort
  for( i = 0; i < nSize; i ++)  {     SortArray(arArray.ElementAt(i)->m_arChildPtrs);  }
}

// Sort
void CFldCmpTree::Sort() {   SortArray(m_arRootPtrs); }

// Parse folder
BOOL CFldCmpTree::ParseFolder(LPCTSTR lpszLeft, LPCTSTR lpszRight)
{
  ASSERT((lpszLeft != NULL) && (lpszRight != NULL));
  if((lpszLeft == NULL) || (lpszRight == NULL))
    return FALSE;

  m_strLeftPath = lpszLeft;
  m_strRightPath = lpszRight;
  if (m_strLeftPath.IsEmpty() || m_strRightPath.IsEmpty())
  {
    m_strLeftPath.Empty();
    m_strRightPath.Empty();
    return FALSE;
  }

  CFldCmpFileTree treeLeft, treeRight;
  treeLeft.ParseFolder(lpszLeft);
  treeRight.ParseFolder(lpszRight);

  return CombineFileTrees(treeLeft, treeRight);
}

// Get node full path
CString CFldCmpTree::GetNodeFullPath(const CFldCmpNodePtr pNode, BOOL bLeft) const
{
  ASSERT(pNode != NULL);
 
  CString str = _T("");
  if(pNode->m_pFather != NULL)
    str = GetNodeFullPath(pNode->m_pFather, bLeft);
  else
    str = bLeft ? m_strLeftPath : m_strRightPath;

  str.TrimRight();
  str.TrimRight(_T("//"));
  str += _T("//");
  str += pNode->m_strName;

  return str;
}

// Set custom compare function
void
 CFldCmpTree::SetCustomSortFunc(PFNFCCMPFUNC pFunc)
{
  ASSERT(pFunc != NULL);
  m_pFnFileCmp = pFunc;
}

 

 

版权声明:© 2004 - 2016 Alva Chien, All Rights Reserved.

相关文章推荐

数据结构 排序比较 c++版

  • 2010年04月18日 13:48
  • 4.46MB
  • 下载

数据结构与算法——普通树的定义与C++实现

用树的第一个儿子和下一个兄弟表示法来表示一个树。 树的节点结构为: struct TreeNode{ TYPE element;//该节点的元素 TreeNode *firstC...

C++数据结构与STL--双向循环链表(实现自定义iterator类)

双向循环链表核心代码图解: 节点类 #ifndef node_H #define node_H template class node { public: no...

算法与数据结构完整源代码C++实现

  • 2010年04月18日 16:42
  • 10.71MB
  • 下载

c++ 数据结构 稀疏矩阵类的定义及其各种操作的实现

稀疏矩阵类:其中实现了矩阵的转置,矩阵的加法,及矩阵的乘法等运算。

C++数据结构——二叉搜索树(实现自定义迭代器)

1.二叉搜索树抽象模型和相应的node对象表示   2.从二叉搜索树删除一个节点    (1)如果是叶子节点就直接删除    (2)被删除的节点有左节点,但没有右节点,则将左...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【C++源代码】文件夹比较、文件比较的数据结构,定义和实现
举报原因:
原因补充:

(最多只允许输入30个字)