[C/C++][文件操作] 对比目录并列出同名较新文件、较旧文件 0.1
作者 523066680@163.com,转载请注明出处:[C/C++][文件操作]目录/文件夹对比并列出同名较新文件、较旧文件 V1
主要是模仿robocopy的部分功能
(robocopy /L 参数可以列出本地目录和备份目录中的异同之处,主要是标记出:较新的、较旧的、多出的文件 )
现在还不会写GUI,打算后面自己做目录树diff,可以手动点选要复制的文件。
同时我也知道有现成的软件,比如meld,但是windows下面不太好用。
特性:
一、支持Unicode字符路径
二、使用了WriteConsoleW函数屏幕输出以保留Unicode字符完整性
(虽然终端上有些Unicode字符看不到,但是标记、粘贴到别的编辑器上面是完整的,至少不会变成问好)
如果是用 wprintf 或者转GBK再printf,则Unicode字符会丢失。
三、判断为当前输出为重定向时,切换到WriteFile函数输出到指定的文件。这一点是因为WriteConsoleW
输出的信息不支持直接重定向,好在conio.h提供了判断输出环境的方法。
这里感谢 flyue 在"终端输出Unicode字符、重定向、标记复制" 方面的指教
编译备注:为了方便Unicode模式,用了 wmain做入口函数,使用mingw g++编译时,加上 -municode 参数,
否则会提示 winMain 未定义。在stackoverflow看到的解决方法。
本来vc的 cl.exe 也可以直接编译,但是居然默认不带dirent.h ... windows有另外一套API,也罢
等我学会了再写一个API的版本。
1 /* 2 g++ CompareW.cpp -municode -o CompareW 3 */ 4 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cwchar> 8 #include <cstring> 9 #include <clocale> 10 #include <fcntl.h> 11 #include <sys/stat.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <windows.h> 15 #include <io.h> 16 17 #define NAME_MAX 1024 18 19 void func( 20 wchar_t path[], 21 const wchar_t dir_a[], 22 const wchar_t dir_b[] 23 ); 24 25 bool FileExists(const wchar_t *wpath); 26 bool FolderExists(const wchar_t *wpath); 27 28 void console_print(const wchar_t str[]); 29 void CheckConsoleRedirect(void); 30 31 void PATH_A_TO_B ( 32 const wchar_t source[], 33 const wchar_t a[], 34 const wchar_t b[], 35 wchar_t newstr[] 36 ); 37 38 DWORD written = 0; 39 static bool g_bRedirect = false; 40 41 int wmain(int argc, wchar_t *argv[] ) 42 { 43 setlocale( LC_ALL, ".936" ); 44 CheckConsoleRedirect(); 45 46 if (argc > 2) 47 { 48 if ( _wopendir(argv[1]) && _wopendir(argv[2]) ) 49 { 50 func( argv[1], argv[1], argv[2]); 51 //wprintf(L"B\n"); 52 //func( argv[2], argv[2], argv[1]); 53 54 fprintf(stderr, "All is done!"); 55 } 56 else 57 { 58 fprintf(stderr, "Argument is not correct!"); 59 } 60 } 61 else 62 { 63 fprintf(stderr, "Arguments not enough!"); 64 } 65 66 return 0; 67 } 68 69 void func( 70 wchar_t path[], 71 const wchar_t dir_a[], 72 const wchar_t dir_b[] 73 ) 74 { 75 _WDIR * a = _wopendir(path); 76 _wdirent * dp; 77 _WDIR * aa; 78 struct stat stA; 79 struct stat stB; 80 81 wchar_t fullpath[NAME_MAX] = L""; 82 83 while (dp = _wreaddir(a)) 84 { 85 if ( 86 wcscmp(dp->d_name, L".") == 0 87 || wcscmp(dp->d_name, L"..") == 0 88 ) 89 { 90 continue; 91 } 92 93 swprintf(fullpath, L"%ls\\%ls", path, dp->d_name); 94 wstat(fullpath, &stA); 95 96 if ( (stA.st_mode & S_IFMT) == S_IFDIR ) 97 { 98 func( fullpath, dir_a, dir_b ); 99 } 100 else 101 { 102 wchar_t full_info[NAME_MAX + 32] = L""; 103 wchar_t mt_str[20] = L""; 104 wchar_t trypath[1024] = L""; 105 106 //swprintf(full_info, L"%ld\t%ls\r\n", stA.st_mtime, fullpath ); 107 PATH_A_TO_B( fullpath, dir_a, dir_b, trypath ); 108 if ( ! FileExists(trypath) ) 109 { 110 swprintf(full_info, L"%8ls : %ls\r\n", L"Extra", fullpath ); 111 console_print( full_info ); 112 } 113 else 114 { 115 wstat(trypath, &stB); 116 if (stA.st_mtime > stB.st_mtime ) 117 { 118 swprintf(full_info, L"%8ls : %ls\r\n", L"Newest", fullpath ); 119 console_print( full_info ); 120 } 121 else if ( stA.st_mtime < stB.st_mtime ) 122 { 123 swprintf(full_info, L"%8ls : %ls\r\n", L"Newest", fullpath ); 124 console_print( full_info ); 125 } 126 else 127 { 128 //Same 129 } 130 } 131 } 132 } 133 _wclosedir(a); 134 135 } 136 137 void console_print(const wchar_t str[]) 138 { 139 if ( ! g_bRedirect ) 140 { 141 WriteConsoleW( 142 GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str) , &written, NULL 143 ); 144 } 145 else 146 { 147 WriteFile( 148 GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str) * sizeof( str[0] ) , &written, NULL 149 ); 150 } 151 } 152 153 void CheckConsoleRedirect(void) 154 { 155 if (!GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &written)) 156 { 157 g_bRedirect = true; 158 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\xFF\xFE", 2, &written, 0); 159 } 160 } 161 162 void PATH_A_TO_B ( 163 const wchar_t source[], 164 const wchar_t a[], 165 const wchar_t b[], 166 wchar_t newstr[] 167 ) 168 { 169 int len_of_a = wcslen( a ); 170 wcscat( newstr, b ); 171 wcscat( newstr, source + len_of_a ); 172 } 173 174 bool FileExists(const wchar_t *wpath) 175 { 176 if (_waccess(wpath, 0) == -1) 177 { 178 return FALSE; 179 } 180 else 181 { 182 return TRUE; 183 } 184 } 185 186 bool FolderExists(const wchar_t *wpath) 187 { 188 return !!(_wopendir(wpath)); 189 }
终端示例(部分内容用省略号表示):
Console\> Compare.exe D:\Duplicate\me H:\me Extra : D:\Duplicate\me\.... Extra : D:\Duplicate\me\.... Newest : D:\Duplicate\me\notes\notebook.txt Older : D:\Duplicate\me\免费获取有声读物.txt |