[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

这个时侯需要C的助攻了

本帖最后由 523066680 于 2017-1-20 16:27 编辑

枚举目录内容,如果是文件在开头给出尺寸,如果是文件夹,在开头给出 DIR 或者 FOLD 的标记,遇到链接自动绕开
输出UNICODE编码的字符。

须使用 g++ 编译
  1. /*
  2.     Code by:523066680@163.com
  3.     2017-01
  4. */
  5. #include <stdio.h>
  6. #include <fcntl.h>
  7. #include <dirent.h>
  8. #include <wchar.h>
  9. #include <sys/stat.h>
  10. #include <sys/types.h>
  11. #include <string.h>
  12. #include <windows.h>
  13. #define NAME_MAX 10240
  14. void func(wchar_t path[]);
  15. void console_print(const wchar_t str[]);
  16. void CheckConsoleRedirect(void);
  17. DWORD written = 0;
  18. static bool g_bRedirect = false;
  19. int wmain(int argc, wchar_t *argv[] )
  20. {
  21.     wchar_t pth[NAME_MAX] = L"D:\\Extra\\";
  22.    
  23.     //首先判断是否为重定向
  24.     CheckConsoleRedirect();
  25.     if ( argc >= 2 )
  26.     {
  27.         if ( argv[1][wcslen(argv[1])-1] == '\\' )
  28.             swprintf(pth, L"%ls", argv[1] );
  29.         else
  30.             swprintf(pth, L"%ls\\", argv[1] );
  31.     }
  32.     func( pth );
  33.     return 0;
  34. }
  35. void func( wchar_t path[] )
  36. {
  37.     DWORD attr;
  38.     _WDIR * a = _wopendir(path);
  39.     _wdirent * dp;
  40.     _WDIR * aa;
  41.     struct stat stbuf;
  42.     wchar_t full_info[NAME_MAX] = L"";
  43.     WCHAR fullpath[NAME_MAX] = L"";
  44.     swprintf(full_info, L"FOLD: %ls\r\n", path );
  45.     console_print( full_info );
  46.     //打印目录内容
  47.     while ( dp = _wreaddir(a) )
  48.     {
  49.         //排除 当前文件夹 和 上一级 文件夹
  50.         if (
  51.                ( wcscmp(dp->d_name, L"." )  == 0 )
  52.             || ( wcscmp(dp->d_name, L".." ) == 0 )
  53.         )
  54.         { continue; }
  55.         swprintf(fullpath, L"%ls%ls", path, dp->d_name);
  56.         wstat(fullpath, &stbuf);
  57.         attr = GetFileAttributesW(fullpath);
  58.         //排除符号链接类型的文件和目录
  59.         if ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) != FILE_ATTRIBUTE_REPARSE_POINT )
  60.         {
  61.             if ( (attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
  62.             {
  63.                 swprintf(full_info, L"%16ls %ls\r\n", L"DIR", dp->d_name );
  64.                 console_print( full_info );
  65.             }
  66.             else
  67.             {
  68.                 swprintf(full_info, L"%16lld %ls\r\n", stbuf.st_size, dp->d_name );
  69.                 console_print( full_info );
  70.             }
  71.         }
  72.     }
  73.     _wclosedir(a);
  74.     //递归流程
  75.     a = _wopendir(path);
  76.     while ( dp = _wreaddir(a) )
  77.     {
  78.         //排除 当前文件夹 和 上一级 文件夹
  79.         if (
  80.                ( wcscmp(dp->d_name, L"." )  == 0 )
  81.             || ( wcscmp(dp->d_name, L".." ) == 0 )
  82.         )
  83.         {
  84.             continue;
  85.         }
  86.         swprintf(fullpath, L"%ls%ls", path, dp->d_name);
  87.         attr = GetFileAttributesW(fullpath);
  88.         //排除符号链接类型的文件和目录
  89.         if ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) != FILE_ATTRIBUTE_REPARSE_POINT )
  90.         {
  91.             if ( (attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
  92.             {
  93.                 swprintf(fullpath, L"%ls%ls\\", path, dp->d_name);
  94.                 func( fullpath );
  95.             }
  96.         }
  97.     }
  98.     _wclosedir(a);
  99. }
  100. void console_print(const wchar_t str[])
  101. {
  102.     if ( ! g_bRedirect )
  103.     {
  104.         WriteConsoleW(
  105.             GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str)  , &written, NULL
  106.         );
  107.     }
  108.     else
  109.     {
  110.         WriteFile(
  111.             GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str) * sizeof( str[0] ) , &written, NULL
  112.         );
  113.     }
  114. }
  115. void CheckConsoleRedirect(void)
  116. {
  117.     if (!GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &written))
  118.     {
  119.         g_bRedirect = true;
  120.         WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\xFF\xFE", 2, &written, 0);
  121.     }
  122. }
复制代码
输出的一部分示例:
  1. Fold: D:\Extra\
  2.        21253 065738_6eeL_1428332.jpg
  3.       362664 1440339f6bzggbp0x16gp3.jpg
  4.       398975 144034a5tty5g2s2azd3bg.jpg
  5.       229915 144037xhfh2jhzh1g1b2jf.jpg
  6.        40421 6cc028c79f3df8dc7a6e5322cd11728b461028c5.jpg
  7.      1853657 7cefdfa5jw1ez6iowueepg206l067qv5.gif
  8.          DIR Book
  9.     11714560 freetype-2.4.0.tar
  10.      2903989 ft27.zip
  11.          DIR graphics
复制代码
如此一来可以顺便写一个文件夹按大小排序的脚本。
1

评分人数

TOP

感谢 happy886rr 的加分。

刚刚测试这个 C 有点问题,在遇到大于 4G 的文件时输出的文件大小不正确(超过4字节的溢出)。
把 stat() 改为 _wstat64()
把 struct stat  改为 struct _stat64
以及 printf 中的 %ld 改为 %lld 即可

TOP

基本完成我要的功能 - 按占用大小来枚举

现在可以设定一个阀值,比如值列出大小超过100MB 且内容疑似相同的文件夹

代码自带混淆,看官自觉绕道
  1. =info
  2.     Code by 523066680@163.com
  3.     2017-01
  4. =cut
  5. use Encode;
  6. use IO::Handle;
  7. use Digest::MD5 qw/md5_hex/;
  8. use YAML::Tiny;
  9. STDOUT->autoflush(1);
  10. print "Getting file list ...\n";
  11. system('listv1.3 D: >D:\a.txt');
  12. our $hash = {};
  13. our @lines;
  14. our %fold_md5;
  15. our %md5map;
  16. my $gstr;
  17. my $ref;
  18. print "Path to struct ...\n";
  19. open READ,"<:raw",'D:\a.txt';
  20. seek(READ, 2, 0);
  21. {
  22.     local $/ = "\x0d\x00\x0a\x00";
  23.     while ($line = <READ>)
  24.     {
  25.         $line =~s/\x0d\x00\x0a\x00//;
  26.         $gstr = encode('gbk', decode('utf16-le', $line));
  27.         if ( $gstr=~s/^FOLD: //i )
  28.         {
  29.             $ref = toStruct( $gstr );
  30.             push @lines, $gstr;
  31.         }
  32.         else
  33.         {
  34.             if ( $gstr=~s/^\s+(\d+) // )
  35.             {
  36.                 $ref->{$gstr} = $1;
  37.             }
  38.             else
  39.             {
  40.                 #nothing to do
  41.             }
  42.         }
  43.     }
  44. }
  45. close READ;
  46. print "Compare ...\n";
  47. compare();
  48. sub compare
  49. {
  50.     my @parts;
  51.     my $ref;
  52.     my $md5;
  53.     print "Getting md5 information ...\n";
  54.     open WRT, ">:raw", "D:\\md5map.txt";
  55.     for my $i ( 0 .. $#lines )
  56.     {
  57.         @parts = split(/[\/\\]/, $lines[$i]);
  58.         $ref = $hash;
  59.         grep { $ref = $ref->{$_} } ( @parts );   #将引用迭代到路径的最后一层
  60.         next if (! keys %{$ref} );               #如果没有下一层文件内容则略过
  61.         
  62.         $md5 = md5_hex( Dump($ref) );
  63.         $fold_md5{ $lines[$i] } = $md5;
  64.         print WRT $md5 ." ". encode('utf8', decode('gbk', $lines[$i])) ."\n";
  65.     }
  66.     close WRT;
  67.     for my $k ( keys %fold_md5 )
  68.     {
  69.         $md5 = $fold_md5{$k};
  70.         push @{ $md5map{$md5} }, $k;
  71.     }
  72.     my $info = { 'sizes' => 0,
  73.                  'folds' => 0,
  74.                  'files' => 0 };
  75.     print "Find same folder\n";
  76.     for my $k ( keys %md5map )
  77.     {
  78.         if ( $#{$md5map{$k}} > 0 )
  79.         {
  80.             @parts = split(/[\/\\]/, $md5map{$k}->[0] );
  81.             $info = { 'sizes' => 0, 'folds' => 0, 'files' => 0 };
  82.             $ref = $hash;
  83.             grep { $ref = $ref->{$_} } ( @parts );
  84.             Summarize( $ref, $info );
  85.             if ( $info->{sizes} > 1024*1024*100 ) #100MB
  86.             {
  87.                 print int($info->{sizes}/1024/1024) ."mb\n";
  88.                 print join("\n", @{$md5map{$k}} );
  89.                 print "\n\n";
  90.                 #dump_byPath( $md5map{$k}->[0] );
  91.             }
  92.         }
  93.     }
  94. }
  95. sub dump_byPath
  96. {
  97.     my $path = shift;
  98.     my $ref = $hash;
  99.     for my $e ( split(/[\/\\]/, $path) )
  100.     {
  101.         $ref = $ref->{$e};
  102.     }
  103.     print Dump( $ref );
  104. }
  105. #获取某个目录的文件大小总和
  106. sub Summarize
  107. {
  108.     my ($ref, $info) = (shift, shift);
  109.     for my $k ( keys %{$ref} )
  110.     {
  111.         if (ref( $ref->{$k} ) eq 'HASH')
  112.         {
  113.             $info->{folds} ++;
  114.             Summarize( $ref->{$k}, $info );
  115.         }
  116.         else
  117.         {
  118.             $info->{files} ++;
  119.             $info->{sizes} += $ref->{$k};
  120.         }
  121.     }
  122. }
  123. sub toStruct
  124. {
  125.     my $path = shift;
  126.     my @parts = split(/[\/\\]/, $path);
  127.     my $ref;
  128.     $ref = $hash;
  129.     for my $e ( @parts )
  130.     {
  131.         if ( not exists $ref->{$e} )
  132.         {
  133.             $ref->{$e} = {};
  134.         }
  135.         $ref = $ref->{$e};
  136.     }
  137.     return $ref;
  138. }
复制代码
输出示例:
  1. 117mb
  2. D:\Local\Dict\Youdao\Source\
  3. D:\Dupl\Dict\有道\
  4. 506mb
  5. D:\Dupl\设计软件\CoreldrawX5+资料\coreldraw x5\coreldraw x5\CGS15\
  6. D:\Program Files (x86)\Corel\CorelDRAW Graphics Suite X5\Setup\CGS15\
  7. 1503mb
  8. D:\3DGameProgramming\Figures\
  9. D:\Data\Books\Book IV\Figures\
  10. 249mb
  11. D:\3DGameProgramming\Figures\Chapter 8 Texturing\
  12. D:\Data\Books\Book IV\Figures\Chapter 8 Texturing\
复制代码
这酸爽,原来我D盘有几个G 的副本……

TOP

回复 18# 523066680
判断大文件可抽样md5,二分法抽样,这样误判几率小于1/pow(2,n),目前对大文件只能做抽样md5检测。

TOP

回复 19# happy886rr


    既然都明确要对比两个文件了,直接用 memcmp 不是更直接吗

TOP

本帖最后由 523066680 于 2017-1-22 22:38 编辑

回复 19# happy886rr


    也想过抽样。好在对于一般的硬盘,上G的文件也多不到哪里去。(先满足个人需求了 )
回老家了,爪机码字

TOP

回复 20# CrLf
这个函数不错嘛。

TOP

本帖最后由 happy886rr 于 2017-1-23 01:55 编辑

回复 21# 523066680
带个本本随地办公吧。不过,我觉得还是回老家有年味,城里都不热闹啊。

TOP

返回列表