多次迭代后的负数

时间:2016-06-27 18:21:25

标签: batch-file cmd

所以我决定制作一个批量生成可能适合某个DVD的电影列表 问题是它有时会返回负数作为文件的大小

@set @x=0 /*
@echo off
@set _thisbatchscript="%~f0"
@setlocal enabledelayedexpansion
@set max=8525510083
@set "parentfolder=%__CD__%"

@set flenght=1
@for /r . %%g in (*.*) do (
@call :gera "%%g"
@set "var=%%g"
@set var=!var:%parentfolder%=!
@set fname[!flenght!]=!var!
@set /a flenght=!flenght!+1
)
@set /a flenght=!flenght!-1

@set movielgt=1
@for /l %%a in (1,1,!flenght!) do (
if !fext[%%a]!==.avi (
@set movienm[!movielgt!]=!fname[%%a]!
@set moviesz[!movielgt!]=!fsize[%%a]!
@set ftemp=!fname[%%a]!
@set ftemp=!ftemp:.avi=!
@set movienoext[!movielgt!]=!ftemp!
@set /a movielgt=!movielgt!+1
)
)
@set /a movielgt=!movielgt!-1

@set subtitlelgt=1
@for /l %%a in (1,1,!flenght!) do (
@if !fext[%%a]!==.srt (
@set subtitlenm[!subtitlelgt!]=!fname[%%a]!
@set subtitlesz[!subtitlelgt!]=!fsize[%%a]!
@set ftemp=!fname[%%a]!
@set ftemp=!ftemp:.srt=!
@set subtitlenoext[!subtitlelgt!]=!ftemp!
@set /a subtitlelgt=!subtitlelgt!+1
)
)
@set /a subtitlelgt=!subtitlelgt!-1

@for /l %%a in (1,1,!movielgt!) do (
@for /l %%b in (1,1,!subtitlelgt!) do (
@if !movienoext[%%a]!==!subtitlenoext[%%b]! (
@set /a moviesz[%%a]=!moviesz[%%a]!+!subtitlesz[%%b]!
)
)
)

set resultlgt=0
for /l %%a in (1,1,!movielgt!) do (
if !moviesz[%%a]! LEQ %max% (
set _tempresultsz=0
set _tempresultnm=
set tamanho=
for /l %%b in (%%a,1,!movielgt!) do (
set /a tamanho+=!moviesz[%%b]!
if !tamanho! LEQ %max% (
set /a _tempresultsz+=!moviesz[%%b]!
set _tempresultnm=!_tempresultnm! !movienm[%%b]!
call :resultpush  "!_tempresultnm!" !_tempresultsz!
)
)
)
)


echo tamanho;arquivos
for /l %%a in (1,1,!resultlgt!) do (
echo !result[%%a]sz!;!result[%%a]nm!
) 


:gera
@set fsize[!flenght!]=%~z1
@set fext[!flenght!]=%~x1
@goto :EOF

:resultpush
@set /a resultlgt+=1
for /f "tokens=* delims= " %%a in ("%~1") do set str=%%a
@set result[!resultlgt!]nm=%str%
REM for /f "delims=" %%i in ('cscript //Nologo //E:jscript %_thisbatchscript% %2') do set _tamanho=%%i
@set result[!resultlgt!]sz=%2
@goto :EOF
REM start of javascript (not in use(too slow to run on evey interation)) 
goto:EOF */
var Size=WScript.Arguments(0);
var result=Size+" Bytes"
if(Size>=1024){
    result=(Size/1024)+" KB";
}
if(Size>=1048576){
    result=(Size/1048576)+" MB";
}
if(Size>=1073741824){
    result=(Size/1073741824)+" GB";
}
if(Size>=1099511627776){
    result=(Size/1099511627776)+" TB";
}
WSH.echo(result);

所以是的,这就是代码 基本上它从它调用的路径获取文件夹和子文件夹中的文件的完整列表,并且迭代它查找.avi和.srt文件,它们总结.avi文件的大小.str具有相同文件夹路径和文件名的文件,最后它再次迭代计算可能适合DVD的文件的可能列表

2 个答案:

答案 0 :(得分:3)

是的,正如SomethingDark建议的那样,你的头撞到了32位整数的极限。您的JScript混合代码可以处理更大的值,最多2 TB(64位)。

如果稍微改变混合格式,可以有多个JScript作业(如果愿意,甚至可以mix JScript and VBScript)。这是一个示范:

<!-- : batch portion
@echo off & setlocal

call :add 2147483647 1234567890 res
call :suffix %res% human
echo %res%, %human%
goto :EOF

:add <int1> <int2> <returnvar>
for /f %%I in ('cscript //nologo "%~f0?.wsf" "%~1" "%~2" //job:add') do set "%~3=%%I"
goto :EOF

:suffix <int> <returnvar>
for /f %%I in ('cscript //nologo "%~f0?.wsf" "%~1" //job:suffix') do set "%~2=%%I"
goto :EOF

: end batch / begin JScript -->
<package>
    <job id="add">
        <script language="JScript">
            WSH.Echo((WSH.Arguments(0) * 1) + (WSH.Arguments(1) * 1));
        </script>
    </job>
    <job id="suffix">
        <script language="JScript">
            var size = WSH.Arguments(0) * 1,
                idx = 0;
            while (size > 1024 && ++idx) size /= 1024;
            WSH.Echo(size.toFixed(1) + ['B','KB','MB','GB','TB'][idx]);
        </script>
    </job>
</package>

顺便说一句,您可以在脚本中进行一些其他改进。首先,并非批处理脚本中的所有内容都必须左对齐。这也可行:

for /f %%I in (
    'cscript //nologo "%~f0?.wsf" "%~1" "%~2" //job:add'
) do (
    set "%~3=%%I"
)

其次,由于您在脚本顶部使用了@echo off,因此您不必为每个命令添加@符号前缀。这就是@echo off

的观点

最后,当使用set /A时,您不必使用周围百分比或感叹号来引用等式中的值。因此,以下三个命令中的每个命令执行完全相同的操作:

set /a flenght=!flenght! + 1
set /a flenght=flenght + 1
set /a flenght+=1

答案 1 :(得分:2)

您的代码有一个基本错误,但它不是其他地方描述的32位整数溢出。

当文件记录在所有类型的光盘(包括DVD)中时,数据总是使用整个磁盘扇区写入,或者更确切地说,整个 (数据块)由整数个磁盘扇区组成。根据{{​​3}}给出的数据:&#34;一个DVD数据块中有16个扇区。一个扇区由2048字节(仅数据)构成,因此一个DVD数据块大小为2048×16字节(= 32768字节)&#34;。标准DVD的总容量是2295104个磁盘扇区,相当于2295104 * 2048 = 4700372992字节(俗称&#34; 4.7 GB&#34;);但是,数据块中DVD 的总容量是2295104/16 = 143444.写在磁盘上的每个文件占用整数个32 KB的数据块,因此数据中每个文件的大小块( not in Bytes)是应该从最初的143444个数据块空闲数量减少的量( 4700372992 Bytes free)。如果您使用不同容量的DVD,只需相应调整值。

这个(正确的)方法还允许使用SET / A命令的32位整数限制来完成所有算术运算。

@echo off
setlocal EnableDelayedExpansion

set /A max=143444, clusterSize=32*1024, allMovies=0

set "flenght=0"
for /R %%g in (*.avi) do (
   set /A "lastFit=flenght, lastFitP1=lastFit+1, flenght+=1, thisMovie=(%%~Zg-1)/clusterSize+1"
   set "fname[!flenght!]=%%~Fg"
   if exist "%%~PNg.srt" for %%s in ("%%~PNg.srt") do (
      set /A "flenght+=1, thisMovie+=(%%~Zs-1)/clusterSize+1"
      set "fname[!flenght!]=%%~Fs"
   )
   set /A "allMovies+=thisMovie"
   if !allMovies! gtr %max% (
      echo/
      echo These files fits in one DVD:
      for /L %%i in (1,1,!lastFit!) do echo !fname[%%i]!

      set "i=0"
      for /L %%i in (!lastFitP1!,1,!flenght!) do (
         set /A i+=1
         set "fname[!i!]=!fname[%%i]!"
      )
      set /A flenght=i, allMovies=thisMovie
   )
)
if %flenght% gtr 0 (
   echo/
   echo These files fits in one DVD:
   for /L %%i in (1,1,%flenght%) do echo !fname[%%i]!
)