2007年2月20日星期二

利用4种小众语言进行批量多层子目录内文件重命名的方法

利用4种小众语言进行批量多层子目录内文件重命名的方法
(华南理工大学建筑学院 qjchen
问题的提出:
有一批txt文件(处于c:\a目录及在此内的多层子目录下),名字是1,2,3,4等比较乱的名字,现在希望用每个文本的第三行文字作为文件的新名字。
(这个要求当然可以是其他比较奇特的,修改一下即可)
为了方便测试,放了一个文件在这里,
http://qjchen.googlepages.com/test.ZIP
请解压到c:\a目录下即可。

现在希望用几种小众语言共同试一下,作为自我学习,也希望各位高手指正、精简及告诉多几种语言的写法。

问题的中心:目录的递归查找文件,文件读取,重命名

1a)纯粹的Lisp语言
既然是Lisp版,当然得先用Lisp语言,此处用的是Vlisp,其中借助了John F. Uhden, Cadlantic的程序。由于VLisp本身只提供了少量的目录函数,因此代码比较长。里面涉及了递归定义。

优点:lisp函数就如一个玩具一样,它用很少的语言定义出一栋高楼大厦,给人有很满足的感觉,当有足够多的Lisp函数构建出函数库,照样有强大的功能。当然,AutoLisp语言的强项在于图形方面,用它来作这些也有点难为它。

缺点:vlisp的速度相对其他语言似乎有些慢。

用法:在autocad2000以上加载之后,运行ren即可。


;;; ========================================================================
;;; Some of the following code are writen by CHEN QING JUN ;
;;; Civil engineering Department, South China University of Technology ;
;;; Purpose: To get a file list of the currrent path ;
;;; The platform: Acad2000 and after ;
;;; 2007.02.19 ;
;;; Http://chenqj.blogspot.com ;
;;; Http://autolisper.googlepages.com ;
;;; ========================================================================
(defun c:ren (/ direc directree x y direcfile)
(setq direc (getstring "\nc:/a:"))
(if (= direc "")
(setq direc "c:/a")
)
(setq directree (@Folders direc))
(foreach x directree
(setq direcfile (qj-directory-only-files x))
(foreach y direcfile
(if (= (vl-filename-extension y) ".txt")
(rename y)
)
)
)
)
(defun rename (y / path fh newname)
(setq path (vl-filename-directory y)
ext (vl-filename-extension y)
)
(setq fh (open y "r"))
(read-line fh)
(read-line fh)
(setq newname (strcat path "/" (read-line fh) ext))
(close fh)
(vl-file-rename y newname)
)
(defun qj-directory-only-files (path / lst res)
(setq lst (vl-directory-files path))
(setq lst (mapcar
'(lambda (x)
(strcat path "/" x)
)
lst
)
)
(foreach x lst
(if (not (vl-file-directory-p x))
(setq res (append
res
(list x)
)
)
)
)
res
)
;;; ========================================================================
;; given the parent folder as a Path. ;
;; Note that using a path of "" or "." or "\\" will exclude ;
;; the drive letter. McNeel's DOSLIB has a DOS_FULLPATH function ;
;; that can return such folders with drive designations. ;
;; (c) John F. Uhden, Cadlantic ;
;;; ========================================================================
(defun @Folders (Path / Folders @Dirs)
(defun @Dirs (Path / Dir Dirs)
(and
(= (type Path) 'STR)
(or
(/= (type DOS_FULLPATH) 'EXRXSUBR)
(setq Path (DOS_FULLPATH Path))
)
(if (wcmatch Path ",*/,*\\")
(setq Dir Path)
(setq Dir (strcat Path "/"))
)
(setq Dirs (vl-directory-files Dir "*.*" -1))
(setq Folders (cons Path Folders))
(setq Dirs (vl-remove-if '(lambda (x)
(vl-position x '("." ".."))
) Dirs
)
)
(mapcar
'@Dirs
(mapcar
'(lambda (x)
(strcat Dir x)
)
Dirs
)
)
)
)
(@Dirs Path)
(reverse Folders)
)


1b)利用doslib程序库
DOSLib, 是一个免费的AutoLISP/Visual Lisp 程序库。它为Autocad提供了各种可供调用的windows操作函数 . 它是用Objectarx编写的AutoCAD应用程序。 DOSLib 通过各种函数扩展了AutoLISP和Visual LISP的编程功能。部分翻译可以见这里:
http://chenqj.blogspot.com/2007/01/doslib-75_27.html

优点:比Lisp的代码要短不少。

缺点:需外挂ARX函数库,对不同版本的arx需要不一样。

用法:对相应的cad版本,加载相应的doslib


;;; ========================================================================
;;; Some of the following code are writen by CHEN QING JUN ;
;;; Civil engineering Department, South China University of Technology ;
;;; Purpose: To rename a batch of txt files into new name according to the ;
;;; third line of the text (Use DOSLIB) ;
;;; The platform: Acad2000 and after ;
;;; 2007.02.19 ;
;;; Http://chenqj.blogspot.com ;
;;; Http://autolisper.googlepages.com ;
;;; ========================================================================
(defun c:ren (/ direc directree x y direcfile fh newname)
(setq direc (getstring "\nc:/a:"))
(if (= direc "")
(setq direc "c:/a")
)
(setq directree (dos_dirtree direc))
(foreach x directree
(dos_chdir x)
(setq direcfile (dos_dir))
(foreach y direcfile
(if (= (vl-filename-extension y) ".txt")
(progn
(setq fh (open y "r"))
(read-line fh)
(read-line fh)
(setq newname (strcat (read-line fh) ".txt"))
(close fh)
(dos_rename y newname)
)
)
)
)
)


2)Python语言
python语言是一种比较新的脚本语言,虽然比较小众,但是也得到越来越多人的应用,个人只学了很少的一部分,感觉其层次清楚,函数库也比较大,语言相对比较灵活,和lisp有点类似,比如list,def,lambda等等都很熟悉。
我用的python版本是activepython:
http://www.activestate.com/
下面的函数walk函数递归调用子程序中的各层文件是参考了
http://www.chinaunix.net/jh/55/574467.html的函数的。

优点:函数库比较多,语言也算比较清晰
缺点:得安装python解释器。

用法:将代码存为.py文件,在activepython里面打开这个文件,按ctrl+R运行即可
注意:python的类似progn之类的操作,是用Tab缩进来描述的,每个缩进代表了一个层次,假如下述代码无法工作的话,请把相应的空格改成Tab,两层的为两个Tab



import os
filedir = "c:\\a"
filenamelist=[]
def visit(arg, dirname, names, flist = filenamelist):
flist += [dirname + "\\" + file for file in names]
os.path.walk(filedir, visit, 0)
for y in filenamelist:
if os.path.isfile(y):
f=open(y,'r')
f.seek(0)
allline=f.readlines()
thirdline=allline[2]
lst=os.path.split(y)
os.chdir(lst[0])
f.close()
os.rename(lst[1] , thirdline.replace("\n", " ")+'.txt')


3)cmd脚本语言
(这个是修改精品和drl的hitme大侠的,for的用法比较奇怪也非常强大)
cmd脚本其实就是批处理语言,在win2000之后得到很大的增强,有许多不可思议的操作都用短短几行就得到了解决,范例可见https://www.dream4ever.org/showthread.php?t=75887
第八楼的帖子,相应还有su99和hitme等高手之作

优点:完全只靠系统本身的批处理语言就解决了问题。
缺点:代码的可读性一般,for的用法非常复制,但也非常强大,好好的学习应该可以解决很复杂的问题(听说黑客整天干这种事,咱可没那种能力和野心:)

用法:将代码存为1.bat文件,放到c:\a目录下,双击运行或者cmd命令行下键入1.bat即可


@echo off
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('dir /s/b *.txt') do (
for /f "skip=1 tokens=1,2 delims=:" %%i in ('findstr /n "." "%%a"') do (
set n=%%j
if "%%i"=="3" (
ren "%%~da%%~pa%%~nxa" "!n:~0,10!.txt" 2>nul)
)
)
endlocal



4)用Autohotkey语言
Autohotkey是一个系统键盘及鼠标模拟程序,具有强大的自定义功能,完全可以将之作为一个Autocad热键处理程序来运行(与Autohook各有所长),外国网站是在这里
http://www.autohotkey.com/wiki/index.php?title=Script_Listing#File_Reading_.26_Parsing
国内也有好些此中高手
http://www.blogcn.com/user48/yonken/index.html
要先安装一个叫autohotkey的软件,下载地址:http://www.autohotkey.com/
它的作用是这样的,
比如把下面这三句代码,存为一个叫abc.ahk (abc可以任意取),
F1::^c
F2::^v
Tab::^l
然后,双击这个abc.ahk,那么它将会认为F1是复制,F2是粘贴,在Autocad中,它会认为Tab键就是和F8键一样的正交键。(你可以用它实现很强大的功能吧:0,不过它和autohook还是不一样的,autohook对于定义单键,比如一个按键的,比如a非常有用,而autohotkey还不行)

本来我想编一个ahk文件来实现用autocad的lisp编辑器批量的autolisp程序的代码格式化的,差一点还没有成功,就先编一个这个来测试一下其目录递归功能,发现也很强大。

优点:语言简洁,更有其他强大的功能
缺点:调试不大方便

用法,将这段代码存为1.ahk文件,双击之则完成


FileList = ; Initialize to be blank.
Loop, c:\a\*.*,0,1
FileList = %FileList%%A_LoopFileFullPath%`n
Loop, parse, FileList, `n
{
FileReadLine, line, %A_LoopField%, 3
B= %A_LoopField%
SplitPath, B, name, path
NewName = %path%\%line%.txt
FileMove, %A_LoopField%, %NewName%
}


其实高手只要精通一种语言就可以为所欲为了,本人只是得处理非常多的文本文件,因此乱七八糟的学了一点皮毛,特别是语言不熟悉时程序也经常拖沓不已,各位见笑了。

总体的感觉,Lisp最顺手,编的最快。Doslib也很熟眼。Python之前编过一些,改改就成功,但是原来的listdir不能用了之后得google,cmd学的好苦,但感觉到有一片新天地,而autohotkey是为了后面的一些批量导出tecplot图形而学习的。除了lisp,好像速度都比较快。

假如有各种其他的代码,也请不吝指教,谢谢。