Board logo

标题: 已结:[转帖求助]一个批量命名的批处理 [打印本页]

作者: chenhui530     时间: 2005-12-5 23:19    标题: 已结:[转帖求助]一个批量命名的批处理

昨晚我在中国电脑俱乐部看到了一个和批处理有关的问题
作者的原话如下:
求一个关于文件批量改名简单的程序(在线等)
情况是这样的:我现在工作需要处理些图片,把图片分类放在许多文件夹里,然后在把每个文件夹里的图片加序号改名,比如一个文件夹名字为AAA111,里面有3个图片,就要把这3图片名字改为AAA111-01,AAA111-02,AAA111-03.我想大致就是把文件名提取,然后在.......真后悔读书的时候没好好掌握一门语言,哎~
前些天图片数量少,我用个更名软件还能应付,最近每天4,5千张,实在是弄不了了,路过的朋友帮帮忙撒.我QQ7885347

当时我也想用批处理解决但是一下想不到怎么提取目录名
就用VBS写了一个
代码如下:
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0
const WindowsFolder=0,SystemFolder=1,TemporaryFolder=2
Set fs = CreateObject("Scripting.FileSystemObject")
Set ws = CreateObject("Wscript.Shell")
set sys = fs.GetSpecialFolder(SystemFolder)
sum = 0
call input()
private sub input()
dim str
str=InputBox( "请输入你要搜索的路径,程序" & vbnewline & "会搜索指定路径的所有子路径","目标目录")
if str <> "" then
   if fs.FolderExists(str) then
      call search(str)
   else
      Msgbox "请输入正确的路径",0,"提示"
      call input
   end if
else
   if msgbox("      您确定退出本程序吗?",4,"提示")=vbyes then wscript.quit
   call input
end if
end sub

Function search(path1)
    dim f1,f2,subfolder,path2,path2file,path2files,renname,foldername,appfile,appfiles,i,j,appfilename,appfilesname
    if right(path1,1) <> "\" then path1 = path1 & "\"
    Set f = fs.GetFolder(path1)
    set appfiles = f.files
    for each appfile in appfiles
        appfilename = path1 & appfile.name
        For j = Len(f) To 1 Step -1 '这里至关重要
            If InStr("\", Mid(f, j, 1)) Then Exit For
        Next
        appfilesname = Mid(f, j + 1, Len(f) - j) '分离出目录名
        if Lcase(fs.GetExtensionName(appfilename)) = "jpg" or Lcase(fs.GetExtensionName(appfilename)) = "bmp" then
        ws.run "cmd /c ren " & appfilename & " " & appfilesname & fs.GetBaseName(appfilename) & "-" & sum & "." &
fs.GetExtensionName(appfilename),0,true
            sum = sum + 1
        end if
    next
    sum = 0       
    Set sf = f.SubFolders
   
    For Each f1 in sf   
        f2 = path1 & f1.name & "\"
        set path2 = fs.getfolder(f2)
        set path2file = path2.files
        for each path2files in path2file
            renname = f2 & path2files.name
            foldername = fs.GetParentFolderName(renname)
            For i = Len(foldername) To 1 Step -1
                If InStr("\", Mid(foldername, i, 1)) Then Exit For
            Next
            foldername = Mid(foldername, i + 1, Len(foldername) - i)
            if Lcase(fs.GetExtensionName(renname)) = "jpg" or Lcase(fs.GetExtensionName(renname)) = "bmp" then
               ws.run "cmd /c ren " & renname & " " & foldername & fs.GetBaseName(renname) & "-" & sum & "." & fs.GetExtensionName(renname),0,true
            sum = sum + 1
            end if         
        next
        sum = 0
        search(f2)
    next

End Function

msgbox "完成操作",0,"提示"

谁能给出批处理代码:

[ Last edited by willsort on 2005-12-9 at 16:09 ]
作者: bush     时间: 2005-12-5 23:34    标题: 提个思路:

dir/a:d /b 〉定向到列表文件
然后再用作批处理参数……
作者: 无奈何     时间: 2005-12-6 11:46
用 Total Commander 很方便的,命名规则处填 [P][C] 就完事了。当然用批处理也不是不可完成,但是确实有这个必要吗?
提取目录名可以试试
for /r %i in (.) do @echo %~ni
作者: chenhui530     时间: 2005-12-6 16:04


  Quote:
Originally posted by bush at 2005-12-5 11:34 PM:
dir/a:d /b 〉定向到列表文件
然后再用作批处理参数……

有必要啊~
使用批处理简单方便些
只是对于SUM的递加和换了目录又重新开始递加不是那么好实现吧
作者: 无奈何     时间: 2005-12-6 17:19
我仍然认为专业的重命名和文件管理软件来做这件事最合适,而用批处理完成这个任务对于批处理不熟悉的人来说无疑增加使用难度。

既然有必要就给你写一个,只作为技术讨论。
:: xrename.cmd -- 按序号重命名文件,并将目录名添加到文件名前。
:: by: 无奈何 - 2005-12-6 - 联系:wunaihe@gmail.com - 环境: NT 以上
@echo off
for /r %%i in (.) do (
        set n=1000
        pushd "%%i"
        for /f "delims=" %%a in ('dir /b *.jpg 2^>nul') do (
                set /a n+=1
                call :rname "%%~ni" "%%~nxa" "%%n:~1%%"
        )
        popd
)
goto :EOF
:rname
ren %2 %1-%3%~x2
goto :EOF
我没有做细节处理,命名格式为 3 位数字,默认只重命名 jpg 文件,漠视重命名失败。有必要自行添加修改。
作者: chenhui530     时间: 2005-12-6 19:33
确实高明~~
作者: willsort     时间: 2005-12-7 21:08
Re 无奈何:

      没有实际测试这段代码,仅仅纸上谈兵提几点建议:

      1、可否在 for /f 中加上文件的路径,以避免 pushd/popd 的使用?
      2、可否将 for /f 改为 for %%a in (files) 的形式?
      3、可否使用 setlocal 启动变量延迟,以避免 call :rname?
      4、如果需要使用 call ,那么可否不用传递变量n,而在 :rname 中直接引用?
作者: 无奈何     时间: 2005-12-8 13:50
for /f "delims=" %%a in ('dir /b *.jpg 2^>nul') do (

to willsort
兄的几点建议真是点点击中要害,实在是比我高明多了。由于写批程序时总是不自觉的向曾经写过的程序片段靠拢,哪怕是有更简洁处理方式也想不到了,看来习惯思维太绊脚了。关于第二点 for /f 也有一点好处,就是可以利用其后 dir /o 参数来定义文件重命名顺序,来增强应用的灵活性,只是在本例无此要求,所以也就无意义了。
修改一下,缩水不少。

  Quote:
@echo off
setlocal ENABLEDELAYEDEXPANSION
for /r %%i in (.) do (
        set n=1000
        for %%a in ("%%i\*.jpg") do (
                set /a n+=1
                ren "%%i\%%a" "%%~ni"-!n:~1!%%~xa
        )
)
goto :EOF

上面的是原贴内容,本来已经完结,zreo 发现有问题并通知了我,居然存在严重 bug 。我仔细研究了一下找到了原因,这同时也是一个有趣的问题,所以我不直接修改原程序了,简单叙述一下这个问题。
请注意一下上面代码红色的部分,我本想省去 for /f 繁琐的命令输出解析,而直接用 for 获取文件名。但这就成了问题的根源,for %%a ... 会获取已经重命名后的文件而再次命名,文件数量多时会造成一直重命名的死循环。所以仍旧采用原先的处理方式,修正如下:

  Quote:

  1. :: xrename.cmd -- 按序号重命名文件,并将目录名添加到文件名前。
  2. rem 2005-12-12 修正并着色
  3. @echo off
  4. setlocal ENABLEDELAYEDEXPANSION
  5. for /r %%i in (.) do (
  6.         set n=1000
  7.         for /f "delims=" %%a in (' dir /b "%%i\*.jpg" 2^>nul ') do (
  8.                 set /a n+=1
  9.                 ren "%%i\%%a" "%%~ni"-!n:~1!%%~xa
  10.         )
  11. )
  12. goto :EOF

[ Last edited by 无奈何 on 2005-12-12 at 21:59 ]
作者: 无奈何     时间: 2005-12-12 02:03
to zreo
你的问题让我发现一个重大 bug ,已经修正了。
作者: zreo     时间: 2005-12-12 11:24
for /F "delims=" %a in ('dir /b *.jpg 2>nul')
这个得不到答案,而且还不能给文件重命名,用了一个得出来的结果是这样的。

  Quote:
I:\>(
set n=1000  
for /F "delims=" %a in ('dir /b *.jpg 2>nul') do (
set /a n+=1  
ren "%a" "图片"-!n:~1!%~xa

在我的机上试了一下,%a得不到文件参数,这样就不能给文件重命名了

  Quote:
echo on
setlocal ENABLEDELAYEDEXPANSION
for /r %%i in (.) do (
        set n=1000
        pushd "%%i"
        for /f "delims=" %%a in ('dir /b *.jpg 2^>nul') do (
                set /a n+=1
                ren "%%a" "%%~ni"-!n:~1!%%~xa
        )
)
goto :EOF

加了一个pushd "%%i"就得到值了。可以解释一下吗?

[ Last edited by zreo on 2005-12-12 at 11:38 ]
作者: 无奈何     时间: 2005-12-12 11:37
to zreo
在批处理文件中要用 %% 替换 % 。
作者: zreo     时间: 2005-12-12 11:40
我在批处理中是用双%%号的,可是%a还是得不到参数,反面加了一句
pushd "%%i"
就可以得到相要的了。
作者: 无奈何     时间: 2005-12-12 14:04
pushd "%%i" 更改了当前路径,然后对当前目录下文件进行更名。
可以用全路径,省去这条语句,我又改了一下。