中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » 一个关于随机获取文件名的问题.
« [1] [2] [3] [4] »
作者:
标题: 一个关于随机获取文件名的问题. 上一主题 | 下一主题
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
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
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
查看资料  发短消息 网志   编辑帖子  回复  引用回复
« [1] [2] [3] [4] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: