生成XML的代码偶尔会生成空文件

时间:2015-06-02 06:38:20

标签: batch-file

我编写了以下批处理脚本,它接受input.xml,修改它,将新文件输出到temp.xml,然后将temp.xml复制到input.xml。

它对我来说很好,但有时它会将一个空的temp.xml文件复制到input.xml,这会导致我丢失数据。

以下是代码:

@echo off
setlocal EnableDelayedExpansion
set dt=%date:~7,2%-%date:~4,2%-%date:~10,4%_%time:~0,2%-%time:~3,2%-%time:~6,2%
cd C:\test\inputFiles
(for /F "delims=" %%a in ('findstr /I /L "<initialTransferReference>" input.xml') do (
set "line=%%a"
set "line=!line:*<initialTransferReference>=!"
for /F "delims=<" %%b in ("!line!") do (
set a=%%b
)))
set /a newvalue=a+1
(for /F "delims=" %%a in (input.xml) do (
set "line=%%a"
set "newLine=!line:initialTransferReference>=!"
if "!newLine!" neq "!line!" (set "newLine=<initialTransferReference>%newvalue%</initialTransferReference>"
)
echo !newLine!
)) > temp.xml
copy /y temp.xml input.xml
del temp.xml
copy /y input.xml "C:\test\modifiedFile\input_%dt%.xml"

为什么脚本有时会将空的temp.xml文件复制到input.xml?

2 个答案:

答案 0 :(得分:0)

JosefZ可能在他的评论中是正确的 - 如果input.xml被另一个进程锁定,您的文件将被空的temp.xml覆盖。但是锁定必须是临时的,否则COPY命令也会失败,原来将保持不变。

我能想到的另一个潜在原因是,如果你的input.xml在进程开始时已经是空的。但是空的input.xml应该是预期的结果。

以下最小的更改将阻止锁定问题。我保留了尽可能多的代码,除了我重新格式化间距和换行符以更好地显示所有这些括号的逻辑。

我在第二个循环周围放了一组额外的括号,只有在内循环成功时才有条件地移动和复制文件。否则我删除临时文件,原始文件保持不变,并且不会创建日期副本。我还使用MOVE代替COPY,然后使用DEL。

请注意,如果无法读取任何行,则2ND FOR / F循环也会返回失败,因此如果input.xml开始为空,则不会创建过时的副本。但是如果找不到<initialTransferReference>行,则不会进行任何更改,但仍会创建过时的副本。

@echo off
setlocal EnableDelayedExpansion
set dt=%date:~7,2%-%date:~4,2%-%date:~10,4%_%time:~0,2%-%time:~3,2%-%time:~6,2%
cd C:\test\inputFiles
(
  for /F "delims=" %%a in ('findstr /I /L "<initialTransferReference>" input.xml') do (
    set "line=%%a"
    set "line=!line:*<initialTransferReference>=!"
    for /F "delims=<" %%b in ("!line!") do (
      set a=%%b
    )
  )
)
set /a newvalue=a+1
(
  (
    for /F "delims=" %%a in (input.xml) do (
      set "line=%%a"
      set "newLine=!line:initialTransferReference>=!"
      if "!newLine!" neq "!line!" (
        set "newLine=<initialTransferReference>%newvalue%</initialTransferReference>"
      )
      echo !newLine!
    )
  ) > temp.xml
) && (
  move /y temp.xml input.xml >nul
  copy /y input.xml "C:\test\modifiedFile\input_%dt%.xml" >nul
) || del temp.xml 2>nul

您的代码可以大大简化。例如,您可以轻松地在一个循环中完成所有操作。

此外,您的代码高度依赖于XML的格式。如果<initialTransferReference>行上有多个标记,或者标记分为多行,则会失败。如果文件包含!,它也将失败。

一个更强大的解决方案可以用批量编写,但我不会打扰 - 它很快变成一个复杂的,神秘的混乱。

我建议您使用我的JREPL.BAT正则表达式文本处理器:-)
JREPL.BAT是纯脚本(混合JScript /批处理),可以在XP之后的任何Windows机器上本机运行。解决方案可以简单:

@echo off
setlocal
set dt=%date:~7,2%-%date:~4,2%-%date:~10,4%_%time:~0,2%-%time:~3,2%-%
call jrepl "\d+(?=\s*</initialTransferReference>)" "Number($0)+1" /j /m /f "C:\test\inputFiles\input.xml" /o - && copy /y "C:\test\inputFiles\input.xml" "C:\test\modifiedFile\input_%dt%.xml"

以上查找结束标记之前的数字,并将其替换为递增的值。如果线路上还有其他标签,它并不在乎。它甚至允许值和结束标记位于不同的行上。

只有在JREPL成功修改input.xml时才会创建日期副本。如果input.xml被锁定,或者由于在</initialTransferReference>之前未找到整数值而未进行任何更改,则不会创建它。

与大多数正则表达式XML&#34;解决方案&#34;一样,仍然可以在其上抛出可能失败的有效XML,但您可能不得不竭尽全力使其失败。它很可能适用于您投入的任何现实世界数据。

如果您真的想要一个强大的解决方案,那么您应该使用VBS,JScript或PowerShell来正确地解析和操作XML。

我不喜欢您如何获取时间戳值,因为它取决于您的语言环境使用的日期和时间格式。但这是一个完全不同的话题。

回复评论中的问题的最新更新

您可以再使用一个JREPL而不是XCOPY将日期字符串附加到Filename标记,并在一个步骤中写入输出文件。请注意我使用行继续来使代码更容易阅读。

@echo off
setlocal
set dt=%date:~7,2%-%date:~4,2%-%date:~10,4%_%time:~0,2%-%time:~3,2%-%
call jrepl "\d+(?=\s*</initialTransferReference>)" "Number($0)+1" /j /m /f "C:\test\inputFiles\input.xml" /o - && ^
call jrepl "(?=\s*</FileName>)" "_%dt%" /m /f "C:\test\inputFiles\input.xml" /o "C:\test\modifiedFile\input_%dt%.xml"

答案 1 :(得分:0)

如果锁定for /F "delims=" %%a in (input.xml) do ( ...文件,

errorlevel 1将无法提升The system cannot find the file input.xml并显示input.xml消息。

great dbenham's answerlukk's answer合并到如果给定文件或目录被锁定,如何检入命令行问题:代码中嵌入的检查循环如下。无人值守timeout ...

@echo off
setlocal EnableDelayedExpansion
set dt=%date:~7,2%-%date:~4,2%-%date:~10,4%_%time:~0,2%-%time:~3,2%-%time:~6,2%
pushd C:\test\inputFiles

:locktest
set "_locktest="
((call )>>"temp.xml" ) 2>nul || set "_locktest=locked"
If defined _locktest (
  echo file is locked; unlock it, please
      rem pause instead of timeout in the next  line?
  timeout /T 5 >NUL 2>&1
  goto :locktest
)
::::::::::::::::::::::::::::::::::
::  your script remainder here  ::
::::::::::::::::::::::::::::::::::
相关问题