您的位置:首页 > 理论基础 > 数据结构算法

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

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

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

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

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

关键问题:
1.文件比较:前面已经说了,类CFldCmpTree支持自定义的比较文件(只限文件之间的比较函数),我提供的默认比较函数使用了位比较(具体的实现是使用了STL里面的bitset,另外一个MFC版本就是直接用CString的Compare比较,可以使用宏_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;
for( int 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()
);
}
for( int 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐