【C/C++】一种同步目录的实现——No“删除整个目录再拷贝”

// 算法是:
//
遍历 dstDir,将所有 srcDir 中不存在的文件删除;
// 遍历 srcDir,若与 dstDir 目录中对应文件的修改日期不一致则替换该文件;
// 忽略 excludeFile 文件里指示的目录和文件。

struct
IgnoreName { bool isDir; tchar fileName[MAX_PATH]; }; bool GetIgnoreNames(const char* excludeFile, std::vector<IgnoreName>& ignoreNames) { bool result = true; ignoreNames.clear(); if (excludeFile) { FILE* fp = NULL; if (_tfopen_s(&fp, Utf8ToTStr(excludeFile).c_str(), _T("rt")) == 0) { char line[MAX_PATH] = {0}; while (fgets(line, MAX_PATH, fp)) { size_t len = strlen(line); if (line[len - 1] == _T('\n')) { line[len - 1] = '\0'; } IgnoreName ignore = {0}; tstring fileName = Utf8ToTStr(line); ignore.isDir = (fileName[0] == _T('\\')); if (ignore.isDir) { fileName = GetFileName(fileName); } _tcscpy_s(ignore.fileName, MAX_PATH, fileName.c_str()); ignoreNames.push_back(ignore); } fclose(fp); } else { g_logHelper.OutputErrorInfo(_T("GetIgnoreNames 打开文件(%s)失败!"), Utf8ToTStr(excludeFile).c_str()); result = false; } } return result; } bool IsIgnoreFile(WIN32_FIND_DATA& findData, const std::vector<IgnoreName>& ignoreNames) { bool isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); std::vector<IgnoreName>::const_iterator it = ignoreNames.begin(); for (; it != ignoreNames.end(); ++it) { if (isDir == it->isDir && _tcsicmp(findData.cFileName, it->fileName) == 0) { return true; } } return false; } bool DeleteDirRecursively(tstring dirPath) { bool result = true; WIN32_FIND_DATA finddata; HANDLE hfind = FindFirstFile(JoinPath(dirPath, _T("*.*")).c_str(), &finddata); if (hfind == INVALID_HANDLE_VALUE) { return result; } do { tstring path = JoinPath(dirPath, finddata.cFileName); if (_tcscmp(finddata.cFileName, _T(".")) == 0 || _tcscmp(finddata.cFileName, _T("..")) == 0) { continue; } if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (! DeleteDirRecursively(path)) { result = false; } } else { if (_tremove(path.c_str()) != 0) { g_logHelper.OutputErrorInfo(_T("DeleteDirRecursively 删除文件(%s)失败!"), path.c_str()); result = false; } } } while (FindNextFile(hfind, &finddata) != FALSE && result); FindClose(hfind); if (result && _trmdir(dirPath.c_str()) != 0) { g_logHelper.OutputErrorInfo(_T("DeleteDirRecursively 删除目录(%s)失败!"), dirPath.c_str()); result = false; } return result; } // 删除dstDir中多余的文件 bool DeleteUnnecessaryFileInDst(tstring srcDir, tstring dstDir, const std::vector<IgnoreName>& ignoreNames) { bool result = true; WIN32_FIND_DATA findData; HANDLE dstFindHandle = FindFirstFile(JoinPath(dstDir, _T("*.*")).c_str(), &findData); if (dstFindHandle != INVALID_HANDLE_VALUE) { do { if (_tcscmp(findData.cFileName, _T(".")) == 0 || _tcscmp(findData.cFileName, _T("..")) == 0 || IsIgnoreFile(findData, ignoreNames)) { continue; } tstring srcPath = JoinPath(srcDir, findData.cFileName); tstring dstPath = JoinPath(dstDir, findData.cFileName); if (! FileExists(srcPath)) { // 删除dstDir目录中的该文件 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result = DeleteDirRecursively(dstPath); } else { result = (_tremove(dstPath.c_str()) == 0); if (! result) { g_logHelper.OutputErrorInfo(_T("DeleteUnnecessaryFileInDst 删除文件(%s)失败!"), dstPath.c_str()); } } } if (result && (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { result = DeleteUnnecessaryFileInDst(srcPath, dstPath, ignoreNames); } } while (FindNextFile(dstFindHandle, &findData) != FALSE && result); FindClose(dstFindHandle); } return result; } bool IsSame(WIN32_FIND_DATA& srcData, WIN32_FIND_DATA& dstData) { // todo! 判断两个文件是否一致,为了高效,目前仅使用文件修改时间的判断 bool result = (srcData.ftLastWriteTime.dwHighDateTime == dstData.ftLastWriteTime.dwHighDateTime); if (result) { result = (srcData.ftLastWriteTime.dwLowDateTime == dstData.ftLastWriteTime.dwLowDateTime); } return result; } // 将dstDir中与srcDir中不一致的文件替换为srcDir中对应的文件 bool SyncDir(tstring srcDir, tstring dstDir, const std::vector<IgnoreName>& ignoreNames) { bool result = true; WIN32_FIND_DATA findData; HANDLE srcFindHandle = FindFirstFile(JoinPath(srcDir, _T("*.*")).c_str(), &findData); if (srcFindHandle != INVALID_HANDLE_VALUE) { do { if (_tcscmp(findData.cFileName, _T(".")) == 0 || _tcscmp(findData.cFileName, _T("..")) == 0 || IsIgnoreFile(findData, ignoreNames)) { continue; } tstring srcPath = JoinPath(srcDir, findData.cFileName); tstring dstPath = JoinPath(dstDir, findData.cFileName); bool shouldCopy = false; WIN32_FIND_DATA dstData; HANDLE dstFindHandle = FindFirstFile(dstPath.c_str(), &dstData); if (dstFindHandle != INVALID_HANDLE_VALUE) { if ((dstData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != (findData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) { if (dstData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result = DeleteDirRecursively(dstPath); } else { result = _tremove(dstPath.c_str()) == 0; if (! result) { g_logHelper.OutputErrorInfo(_T("SyncDir 删除文件(%s)失败"), dstPath.c_str()); } } shouldCopy = true; } else if ((dstData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 && !IsSame(findData, dstData)) { shouldCopy = true; result = _tremove(dstPath.c_str()) == 0; if (! result) { g_logHelper.OutputErrorInfo(_T("SyncDir 删除文件(%s)失败"), dstPath.c_str()); } } FindClose(dstFindHandle); } else // dstPath对应文件或者目录不存在 { shouldCopy = true; } if (result && shouldCopy) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result = _tmkdir(dstPath.c_str()) == 0; if (! result) { g_logHelper.OutputErrorInfo(_T("SyncDir 创建目录(%s)失败"), dstPath.c_str()); } } else { result = ::CopyFile(srcPath.c_str(), dstPath.c_str(), TRUE) != FALSE; if (! result) { g_logHelper.OutputErrorInfo(_T("SyncDir 复制文件(%s)到(%s)失败"), srcPath.c_str(), dstPath.c_str()); } } } if (result && findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result = SyncDir(srcPath, dstPath, ignoreNames); } } while (FindNextFile(srcFindHandle, &findData) != FALSE && result); FindClose(srcFindHandle); } return result; } bool RestoreDir(const char* srcDir, const char* dstDir, const char* excludeFile/* = NULL*/) { std::vector<IgnoreName> ignoreNames; if (! GetIgnoreNames(excludeFile, ignoreNames)) { return false; } bool result = DeleteUnnecessaryFileInDst(Utf8ToTStr(srcDir), Utf8ToTStr(dstDir), ignoreNames); if (result) { result = SyncDir(Utf8ToTStr(srcDir), Utf8ToTStr(dstDir), ignoreNames); } return result; }
原文地址:https://www.cnblogs.com/jeJee/p/2675145.html