|
zh159
金牌会员
积分 3687
发帖 1467
注册 2005-8-8
状态 离线
|
『第
31 楼』:
voiL 在 10 楼说的无奈何版主代码"编号"问题,估计 voiL 是在“echo %random%:%*”一行后面>>List.txt了应该是在“@echo %%b”后面>>List.txt
看 25 楼
|
|
2006-7-28 09:48 |
|
|
220110
荣誉版主
积分 718
发帖 313
注册 2005-9-26
状态 离线
|
『第
32 楼』:
获取目录下所有的mp3文件数量,用 for /r %%i in (*.mp3) do set /a n+=1 来取代:
[1] for /f "tokens=1 delims= " %%i in ('dir *.mp3^|find "个文件"') do set 文件数量=%%i
[2] dir /b *.mp3 | findstr /n "." >tem.txt
for /f "tokens=1 delims=:" %%g in (tem.txt) do set maxnum=%%g
[3] for /f "delims=" %%i in ('dir /b /a-d') do @call :sub %%i
是否效率会高点?请willssort作下深入剖析.
|
|
2006-7-28 10:01 |
|
|
namejm
荣誉版主
batch fan
积分 5226
发帖 1737
注册 2006-3-10 来自 成都
状态 离线
|
『第
33 楼』:
Quote: | Originally posted by zxcv at 2006-7-28 09:42:
说实话,那是我说明本行的作用发贴时加上去的,真正的BAT中本来就没有(所以我的说明:红色部分不要);不过你应该可以看得懂邠... |
|
如果只是加注释,可以在语句的上一行或下一行用 :: 注释内容 或者 rem 注释内容 的格式。
[ Last edited by namejm on 2006-7-28 at 10:35 ]
|
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。 |
|
2006-7-28 10:32 |
|
|
namejm
荣誉版主
batch fan
积分 5226
发帖 1737
注册 2006-3-10 来自 成都
状态 离线
|
『第
34 楼』:
和bagpipe探讨了无奈何版主25楼的代码,发现这段代码还有可精简的地方,把bagpipe精简后的代码发一下:
1、
@echo off
setlocal enabledelayedexpansion
copy nul List.txt >NUL
if "%1" NEQ "$" (
for /f "tokens=1,2 delims=:" %%a in ('"%~0" $^|sort') do echo %%b>>List.txt
) else for /f "delims=" %%i in ('dir /b /a-d *.mp3') do echo !random!:%%i 2、
@echo off
copy nul List.txt >NUL
if "%1" NEQ "$" (
for /f "tokens=1,2 delims=:" %%a in ('"%~0" $^|sort') do echo %%b>>List.txt
) else for /f "delims=" %%i in ('dir /b /a-d *.mp3') do call echo %%random%%:%%%%i
|
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。 |
|
2006-7-28 14:16 |
|
|
doscc
中级用户
积分 256
发帖 93
注册 2006-3-26 来自 广东
状态 离线
|
『第
35 楼』:
Quote: | Originally posted by 无奈何 at 2006-7-27 23:51:
@echo off
if "%1" NEQ "$" (
for /f "tokens=1,2 delims=:" %%a in ('"%~0" $^|sort') do @echo %%b
) else for /f "delims=" %%i in ('dir /b /a-d') do @call :sub %%i
goto :EOF
:sub
echo %random%:%*
goto :EOF
|
|
无奈兄 的代码 真的很高明! 不愧是版主!
高明之处 ('"%~0" $^|sort') 和 echo %random%:%* 前乎后应也!
简单解析一下代码:
获得所有文件 在每个文件前标上 随机数 再排列 过虑输出!
[ Last edited by doscc on 2006-7-28 at 16:18 ]
|
|
2006-7-28 16:13 |
|
|
doscc
中级用户
积分 256
发帖 93
注册 2006-3-26 来自 广东
状态 离线
|
『第
36 楼』:
Re: namejm & bagpipe
call echo %%random%%:%%%%i 这句用得很好!
|
|
2006-7-28 16:22 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
37 楼』:
Quote: | Originally posted by 220110 at 2006-7-28 10:01:
获取目录下所有的mp3文件数量,用 for /r %%i in (*.mp3) do set /a n+=1 来取代:
[1] for /f "tokens=1 delims= " %%i in ('dir *.mp3^|find "个文件"') do set 文件数量=%%i
[2] dir /b *.mp3 | findstr /n "." >tem.txt
for /f "tokens=1 delims=:" %%g in (tem.txt) do set maxnum=%%g
[3] for /f "delims=" %%i in ('dir /b /a-d') do @call :sub %%i
是否效率会高点?请willssort作下深入剖析. |
|
Re 220110『第 32 楼』:
关于上述几段代码的问题,我有以下几点浅见:
1、从算法角度上来看,各段代码的时间复杂度是一致的,所以他们真正的运行效率主要取决于系统支持上的细节;
2、从代码角度上来看,兄的代码效率上的优势在于没有使用文本的的输入输出操作;而众所周知的是,I/O向来是影响代码效率的瓶颈之一,这是其他的几段代码所不及的。在其他的代码中,代码[1]的效率应该强于代码[2],因为代码[2]不仅对dir的输出文本作了编辑(加行号),而且for/f的文本处理量也明显大于代码[1];至于代码[3]的用法,因为涉及到了批处理的递归调用(其本质是数据读取),所以其效率也低于代码[1]。
3、但在实际的测试中,结果并不完全像2所分析的那样。在小规模的测试中(Audio目录,文件数746),兄的代码效率最高(140ms),其次却并非代码[1](234ms),而是代码[2](218ms)。分析其结果,原因就在于,代码[2]并非直接用for/f分析findstr的结果,而是使用了临时文件temp.txt,而操作系统为了改善文件IO的效率,会在内存中开辟出相应的文件IO缓冲区,以提高文件的访问速度,而代码[1]因为无法“享受到这种优惠政策”而导致了初段赛跑的落后。这是一个典型的因为系统特性而影响代码效率的例子。
4、而在一些大规模的测试中(整盘测试,文件数>60000),情况再次发生了变化。首次的测试结果是,兄的代码>代码[1]>代码[2],但是随后的测试中,情况就变成了代码[1]>兄的代码>代码[2]。其原因在于操作系统针对dir等大规模的文件I/O行为设计了位于硬盘上的预存取(Prefetch)机制,由于兄的代码无法“借光”,所以在旗开得胜之后便一蹶不振了。而代码[2]的因为规模的增大暴露出其文件处理算法上的落后。这是另一个比较典型的因为系统特性而影响代码效率的例子。
5、在实用角度上来看,兄的代码因为for不遍历隐藏和系统属性的文件,所以其结果会在一些复杂的应用场合中发生偏差。代码[2]中因为缺少/a-d开关,因为会将目录也计入文件数中。另外,如果在代码[1]的dir开关中,加入/w会对效率的提升有些帮助,而加入开关/-c,则可以去除结果中的逗号分隔符。而如果将代码[1]改为代码[2]的临时文件机制,则效率可以得到进一步提升。所以,综合各方案的我的修改后的方案如下:
@echo off & setlocal
dir %1 /a/s/w/-c | findstr "个文件">temp.txt
for /f %%i in (temp.txt) do set filenum=%%i
echo.FileNum:%filenum%
if exist temp.txt del temp.txt [ Last edited by willsort on 2006-7-29 at 01:27 ]
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-7-28 19:49 |
|
|
220110
荣誉版主
积分 718
发帖 313
注册 2005-9-26
状态 离线
|
『第
38 楼』:
Re willsort:
不知道你有没有测试深层多层子目录下的情况?
总觉得for /r 比 dir /b /a:-d 来得效率要高,排除你的第五点提的系统属性影响。
我只在根目录对系统盘测试了下,系统盘算足够多的文件和足够深的路径了吧;暂无其它新测试办法和环境对比。
Re namejm & bagpipe:
你们确实不错!还能精简。
只是,你们忽略了无奈何的初衷——不使用临时文件。
看你们不用临时文件,还能怎么精简!!激将一下,哈
[ Last edited by 220110 on 2006-7-29 at 00:25 ]
|
|
2006-7-29 00:23 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
39 楼』:
Re 220110:
在你回复之前,就开始对原稿进行重新编辑,之后才看到你的回复,其中对你提到的新问题略有提及。
至于 namejm & bagpipe 兄 对 无奈何兄的代码精简,其实并未涉及临时文件,代码中的list.txt,实际上是保存结果数据的文件,而无奈何兄的原方案是直接将他们输出至控制台上的。
而无奈何兄的让namejm兄所难以理解的if/lse结构,才真正是避免临时文件的关键。也就是说,如果使用临时文件,则可以不使用if/lse结构,比如我编辑过的以下代码。
另外,无奈何兄的代码最突出的特点,不在于简洁或者晦涩,而在于其反其路而行之的高效算法,不再去控制随机数的生成,而是去控制列表的生成,这是其它几段代码都无法比及的。
@echo off
cd.>temp.txt & cd.>list.txt
for /f "delims=" %%i in ('dir *.mp3 /b/a-d') do call echo %%random%%%%random%%:%%i>>temp.txt
sort < temp.txt > temp1.txt
for /f "tokens=1,2 delims=:" %%a in (temp1.txt) do echo %%b>>list.txt
for %%f in (temp?.txt) do del %%f [ Last edited by willsort on 2006-7-29 at 01:48 ]
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-7-29 01:46 |
|
|
namejm
荣誉版主
batch fan
积分 5226
发帖 1737
注册 2006-3-10 来自 成都
状态 离线
|
『第
40 楼』:
看了willsort版主39楼的代码,才知道制造空文本文件还可以用cd.>这样的方法,开眼了。
无奈何版主的代码确实很高明,抛开按顺序打印行号之后再乱序选取的常规思路,而直接乱序命名行号再重列,是乱中求顺而达到乱序排列的目的,此法的效率和常规解法的效率不是同一个数量级的。不过,因为调用自身的缘故,去掉开头的@echo off一句之后,就会得到错误的结果,因此,这段代码只能作为一个独立的脚本来使用,而不能作为某个脚本中内部的子段来调用。如果能做出可循环调用的子段的话,就十分完美了。
搭个车问个问题:重定向符号<和>在同一条语句中接连使用的方法,不怎么熟悉,哪位能讲解一下不?主要讲一下使用环境、有没有什么条件的限制等。
|
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。 |
|
2006-7-29 20:44 |
|
|
无奈何
荣誉版主
积分 1338
发帖 356
注册 2005-7-15
状态 离线
|
『第
41 楼』:
还是 willsort 兄的总结最点到要害。
不好意思的说,我给出的代码我并没有太多的关注效率问题,只是不想生成临时文件。这段代码只是一个典型的递归调用的例子,看讨论已经解释的比较清楚了,不再多言。如果在不在意生成临时文件的情况下 willsort 兄 39 楼给出的代码无疑是最简单且容易操控的。
关于 namejm 兄与 bagpipe 兄的精简我是很喜欢这种精神的,可以改善代码的质量,提高代码的编写水平,并且不时还会有新的发现。当然这其中会有代码书写习惯的问题,就像我非不得以的情况我会尽量避开延缓环境变量的使用,而更喜欢调用外部代码段,这样的程序结构看起来更好看一点,效率问题我还没有深入的研究过。再者 namejm 兄 34 楼 代码段 2、中 %%random%%:%%%%i 句是有问题的,当含有 1.mp3、2.mp3 这样的文件时文件名会丢失,原因是参数 i 多次被转义,修正是去掉两个 % ,参见 39 的代码。
|
☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul
|
|
2006-7-29 22:17 |
|
|
HUNRYBECKY
银牌会员
积分 1179
发帖 442
注册 2006-9-9
状态 离线
|
『第
42 楼』:
willsort兄的代码的确精简也很精彩,但是有个问题。如果要获取某个盘下所有子目录的文件则有问题,结果输出只有盘符。
|
|
2006-12-10 03:13 |
|
|
zh159
金牌会员
积分 3687
发帖 1467
注册 2005-8-8
状态 离线
|
『第
43 楼』:
把俺最新的也加入这贴吧^_^
@echo off
for /f "delims=" %%i in ('dir/a-d/b *.mp3') do call set $%%random%%$%%i=$
for /f "tokens=1,2* delims=$=" %%i in ('set $') do echo %%j
pause
|
|
2006-12-10 14:29 |
|
|
3742668
荣誉版主
积分 2013
发帖 718
注册 2006-2-18
状态 离线
|
『第
44 楼』:
利用sort /+n 也能一定程度上的随即列表。
@echo off
set /a num=%random% %% 4 + 1
dir /b /a-d | sort /+%num%
pause
exit /b 0 它要求文件名相似度不能太高。
|
|
2006-12-10 14:57 |
|
|
qzwqzw
银牌会员
天的白色影子
积分 2342
发帖 635
注册 2004-3-6
状态 离线
|
『第
45 楼』:
可以考虑使用不同的%num%反复sort来增大随机度。
|
|
2006-12-10 16:05 |
|