1

编辑 1

步骤 1:电话对话以 .WAV 格式记录在特定文件夹和子文件夹中(由录音软件以当前日期格式自动创建,即20121119 (YYYYMMDD)。此命名约定不能更改。当前日期子文件夹会自动创建在D盘中名为RECFILED的文件夹中。比如说,如果是今天的录音,则文件将存储在20121119子文件夹中。昨天的文件存储在20121118中。

第 2 步:最后,这些 *.WAV 文件需要转换为 *.MP3 格式并上传到 Amazon S3。目前这个过程是手动的。由于 WAV 文件很多,所以我使用 SOX 将 WAV 批量转换为 MP3。为此,我创建了一个批处理文件(在我的原始问题中进行了解释),以便可以自动化此转换过程。此批处理文件将 WAV 转换为 MP3,并将 MP3 文件保存在与 WAV 文件相同的文件夹中。为此,我要做的就是复制文件夹中的批处理文件并运行它。它转换文件并将其保存在同一文件夹中。

第 3 步:文件转换完成后。然后在 Amazon S3 上的特定存储桶中,我必须创建一个具有当前日期的新文件夹,以便可以将所有这些 MP3 存储在那里。但是,这里的日期格式是 DD.MM.YYYY。文件夹层次结构是\BucketName\Voice\201211\19.11.2012\*.MP3(今天)\BucketName\Voice\201211\20.11.2012\*.MP3(明天)等等。

现在,问题是:

  1. 遍历最新的文件夹(查看 d:\RecFileD\YYYYMMDD)并查看文件夹中是否有可用的 WAV 文件。如果是,则将这些文件转换为 MP3 并将它们存储在本地服务器上任何特定位置的名为 DD.MM.YYYY 的文件夹中。(今天的日期,但格式不同)。

  2. 一次,创建文件夹(使用 DD.MM.YYYY 命名约定。相同的文件夹需要在特定月份(即 201211)上传到 S3。一旦月份发生变化,比如 12 月,与 12 月相关的文件将进入文件夹 201212 等等。

  3. 这里的问题是,在本地服务器上,命名约定是 YYYYMMDD(不带空格、点或逗号),而在 S3 上,命名约定是 DD.MM.YYYY(带点)。

原始问题

请帮我编写一个批处理文件,以便我可以自动化将 WAV 文件转换为 MP3 的过程,然后将它们直接上传到 Amazon S3 到特定文件夹。现在它是一个手动过程。

实际上,我们正在运行一个小型呼叫中心,所有语音呼叫都记录并保存在服务器上的D:驱动器中的文件夹RecFileD中,并以当前日期命名的子文件夹(即,20121117等等20121116)。默认情况下,文件以 WAV 格式保存。在将文件上传到 Amazon S3 进行存储之前,我需要将文件转换为 MP3。

要求是我需要每天在一天结束的特定时间在 S3 上上传 MP3 文件。问题是如何遍历到最后一个文件夹(当前日期文件夹)并转换文件。在本地服务器上,语音文件保存在d:\RecFileD\20121117\*.wavAmazon S3 上,文件上传到文件夹中:

  • \BucketName\Voice\201211\17.11.2012\*.mp3(这是十一月);

  • \bucketName\Voice\201212\01.12.2012\*.mp3(这将是 12 月)(全天 31 个文件夹)。

为了自动转换,我创建了以下批处理文件。此文件使用 SOX 应用程序将 WAV 文件转换为当前文件夹中的 MP3。

@echo off
call :treeprocess
goto :eof

:treeprocess
for %%f in (*.wav) do 
(
  sox %%~nf.WAV %%~nf.mp3
  sox %%~nf.WAV %%~nf-short.mp3 trim 0:30 1:00
)

for /D %%d in (*) do 
(
  cd %%d
  call :treeprocess
  cd ..
)
exit /b

为了自动将文件上传到 S3,我将使用 S3 命令行工具。

简而言之,需要以下步骤:

  1. 仅遍历本地服务器上的当前日期文件夹(20121115、、2012111620121117)并将 WAV 文件转换为 MP3(使用上述脚本)。

  2. 17.11.2012将这些 MP3 文件移动到自动命名为(根据当前日期)创建的单独文件夹。

  3. 将文件夹上传到特定位置的 Amazon S3。即,\bucketname\voice\201211\17.11.2012

4

2 回答 2

0

你所拥有的非常好,你已经很接近了。

我正在测试的环境需要do (将 open paren 与 do 放在同一行。中间有换行符的格式可能会导致问题。

您完全缺少的是对预期为 YYYYMMDD 的目录名称的任何解析。你可以这样做:

set dirname=%%d

set year=%dirname:~0,4%
set month=%dirname:~4,2%
set day=%dirname:~6,2%

完成此操作后,很容易根据 YYYY、MM、DD 创建文件名和路径:

set s3path=!file_year!!file_month!\!file_day!.!file_month!.!file_year!

将生成类似 YYYYMM\DD.MM.YYYY 的路径。

您可以使用以下方法获取“最后一个”目录:

for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
  set dirset=%%a
)

注意:这仅在第二种解决方案中实现。让我们分解一下:

dir /b /a:d /o:n ????????

是否以“裸”格式创建目录(仅匹配文件列表,每行一个),具有属性目录(仅列出目录),按名称排序(这是 NTFS 的默认设置,但不是 FAT,因此最好指定排序顺序),匹配 ??????????,任意 8 个字符(因为目录应该命名为 YYYYMMDD,所以总是 8 个字符)。这将返回 8 个字符的目录名称的有序列表。

for /f "tokens=1" %%a IN ('command') do echo %%a

command逐行执行并解析结果。这里将回显每个结果的第一个标记。

for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
  set dirset=%%a
)

我们将它们放在一起,看看dirset将设置为每个匹配的目录名称。但是在for循环完成后,它将被设置为最后一个值,或“最新”目录。

在下面的代码中我已经dirname单独设置以避免变量扩展规则的问题。或者,您应该能够使用:

setlocal enableextensions enabledelayedexpansion 

set dirname=%%d
set year=!dirname:~0,4!

如前所述,您的问题不需要递归。我的代码只是迭代每个目录,然后迭代每个文件。如果文件布局的结构不如您指出的那样,则可能需要递归。

您没有指定您使用哪个 Windows S3 命令行工具,所以我*S3COPY*使用本地完整路径和部分路径进行回应。您应该可以用您的复制命令替换它。

您需要从中运行它,d:\RecFileD或者您可以在 bat 文件顶部附近添加它:

d:
cd \RecFileD

您可能需要更改s3root为本地 S3 副本的实际根目录。我没有移动文件,而是让 sox 在正确的位置创建它们。

我设置了年、月、日变量,processfiles因为变量扩展规则使设置它们processdirs变得复杂。

如果您做的远不止这些,我建议您研究 Python。它有一个很棒的社区/生态系统,很容易上手并且是免费的。另外,您不会把所有的时间都花在与语言打架上。

这是我的第一次尝试:

@echo off

setlocal

set s3root=d:\s3\bucket\voice

call :processdirs
goto :eof

:processfiles
  set year=%dirname:~0,4%
  set month=%dirname:~4,2%
  set day=%dirname:~6,2%

  set s3path=%year%%month%\%day%.%month%.%year%
  set s3dir=%s3root%\%s3path%
  if not exist "%s3dir%" md "%s3dir%"

  for %%f in (*.wav) do (
    sox "%%~nf.WAV" "%s3dir%\%%~nf.mp3"
    sox "%%~nf.WAV" "%s3dir%\%%~nf-short.mp3" trim 0:30 1:00
  )

  echo *S3COPY* %s3dir% %s3path%
  goto :eof

:processdirs
  for /D %%d in (*) do (
    set dirname=%%d
    cd "%%d"
    call :processfiles
    cd ..
  )
  goto :eof

@Aacini 的回答让我意识到,不幸的是我的解决方案缺乏。它不仅仅处理今天的文件。但我很关心跳过一天会发生什么。

我添加了两个参数来控制处理的内容。第一个参数指定一个命名过滤器,可以是以下之一:

  • newlatest - 最新目录中的新文件,基于文件名(默认)
  • latest - 最新目录中的所有文件,基于文件名
  • today - 今天的目录
  • newdirs - S3 树中不存在的所有目录(缺失日期)
  • newfiles - S3 树中不存在的所有文件
  • all - 所有文件(用于覆盖 S3 树中的损坏)

如果过滤器是newdirs,newfilesall,则可以使用第二个参数来进一步过滤目录名称。您可以使用 * 和 ? 通配符匹配一组文件。

如果您将脚本保存为 ProcDirs.bat,那么这里有一些示例:

ProcDirs all 20121119
将强制处理(或重新处理)指定目录。

ProcDirs newdirs 201211??
将处理与目录名称匹配的新目录(从输出树中丢失)(指定年份和月份的任何一天)。

ProcDirs newfiles 2012????
将处理与目录名称匹配的目录中的新文件(从输出树中丢失)(指定年份的任何一天)。

ProcDirs
ProcDirs newlatest
完全相同,因为newlatest是默认值。这将处理(词法上)“最新”目录中的新文件

代码比较复杂,但还不错。我确实尝试使用@Aacini 的代码来获取今天的月/日/年,但它在我的系统上不起作用(因为我的日期格式必须与要求的不同)。所以我使用了一种不依赖于本地日期格式的不同方法。

我的第一个解决方案不需要延迟扩展,但是这个解决方案需要使用setlocal(适用于 Win XP 但可能不适用于较旧的 Windows)并使用!而不是%用于环境变量替换。

@echo off

setlocal enableextensions enabledelayedexpansion

set s3root=d:\s3\bucket\voice

rem Set the default filter mode

set newfilter=none
set dirsetfilter=none

set arg=%1
if "!arg!" == "" set arg=newlatest

if "!arg!" == "newdirs" (
  set newfilter=newdirs
) else if "!arg!" == "newfiles" (
  set newfilter=newfiles
) else if "!arg!" == "all" (
  set dirsetfilter=none
  set newfilter=none
) else if "!arg!" == "today" (
  set dirsetfilter=today
) else if "!arg!" == "latest" (
  set dirsetfilter=latest
) else if "!arg!" == "newlatest" (
  set newfilter=newfiles
  set dirsetfilter=latest
)

if !dirsetfilter! == today (
  for /f "skip=1 tokens=1-3" %%a IN ('wmic path Win32_LocalTime Get Day^,Month^,Year /Format:table') do (
    if %%a GTR 0 (
      set now_day=%%a
      set now_month=%%b
      set now_year=%%c
    )
  )
  set dirset=!now_year!!now_month!!now_day!
  if not "%2" == "" echo Second parameter, dirset, ignored when filter is today
) else if !dirsetfilter! == latest (
  rem pull out the name of the 'last' directory
  for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
    set dirset=%%a
  )
  if not "%2" == "" echo Second parameter, dirset, ignored when filter is latest
) else if not "%2" == "" (
  rem The second parameter is dirset. Wild card chars, *? allowed
  rem only matched dir(s) processed
  set dirset=%2
) else (
  rem process all dirs that match filter
  set dirset=*
)

call :processdirs
goto :eof

:processfiles
  set file_year=!dirname:~0,4!
  set file_month=!dirname:~4,2!
  set file_day=!dirname:~6,2!

  set s3path=!file_year!!file_month!\!file_day!.!file_month!.!file_year!
  set s3dir=!s3root!\!s3path!

  set skipdir=FALSE
  if not exist "!s3dir!" (
    md "!s3dir!"
  ) else (
    if newdirs == !newfilter! set skipdir=TRUE
  )

  if !skipdir! == FALSE (
    set havenewfiles=FALSE

    for %%f in (*.wav) do (
      set skipfile=FALSE
      if newfiles==!newfilter! if exist "!s3dir!\%%~nf.mp3" set skipfile=TRUE
      if !skipfile! == FALSE (
        set havenewfiles=TRUE
        echo sox "%%~nf.WAV" "!s3dir!\%%~nf.mp3"
        sox "%%~nf.WAV" "!s3dir!\%%~nf.mp3"
      )

      set skipfile=FALSE
      if newfiles == !newfilter! if exist "!s3dir!\%%~nf-short.mp3" set skipfile=TRUE
      if !skipfile! == FALSE (
        set havenewfiles=TRUE
        echo sox "%%~nf.WAV" "!s3dir!\%%~nf-short.mp3" trim 0:30 1:00
        sox "%%~nf.WAV" "!s3dir!\%%~nf-short.mp3" trim 0:30 1:00
      )
    )

    if !havenewfiles! == TRUE (
      echo *S3COPY* !s3dir! !s3path!
    )
  )
  goto :eof

:processdirs
  for /D %%d in (!dirset!) do (
    echo Process Dir: %%d
    set dirname=%%d
    cd "%%d"
    call :processfiles
    cd ..
  )
  goto :eof

祝你好运。我希望这有帮助。

于 2012-11-17T20:50:40.603 回答
0

哇!这听起来比实际复杂得多!

@echo off
rem Create folder names from current date, MM/DD/YYYY locale format is assumed
for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
   set YYYYMMDD=%%c%%a%%b
   set YYYYMM=%%c%%a
   set DD.MM.YYYY=%%b.%%a.%%c
)
rem Enter into target folder
cd /D D:\RecFileD\%YYYYMMDD%
rem Convert WAV files to MP3 using SOX
for %%f in (*.wav) do (
   sox %%~nf.WAV %%~nf.mp3
   sox %%~nf.WAV %%~nf-short.mp3 trim 0:30 1:00
)
rem Move MP3 files to brother folder
md ..\%DD.MM.YYYY%
move *.mp3 ..\%DD.MM.YYYY%
rem Upload the folder to Amazon S3
echo S3COPY from ..\%DD.MM.YYYY% to \bucketname\voice\%YYYYMM%\%DD.MM.YYYY%

我建议您在描述问题时尽可能简洁,但不要忘记任何细节。例如,在您的(长)描述中,命名的本地文件夹17.11.2012还不够解释!

我希望这是你想要的...

安东尼奥

于 2012-11-17T22:17:14.733 回答