如何使用Windows中的批处理命令从非文本文件中获取一些文本信息?

时间:2011-02-18 02:37:38

标签: batch-file

人。 我试图从一些非文本文件中获取文件版本。 在每个中(大约在开头),有一些文本行包含有关该文件的信息。 例如:

[some nontext data (very few)]
version: 455467
build date: 23.11.2010
.....
[rest of the nontext data]

如果你想我会尝试制作这样的文件,但我无法向你展示原始文件(我的公司不会允许它)。遗憾...

我试过这段代码:

@echo off
for /f "tokens=1,2" %%A in (file.dat) do if %%A==version: (set version=%%B
goto found)
echo not found
goto end
:found
echo found: %version%
:end
pause

但是只有当“file.dat”是一个文本文件时它才有效,如果不是“我找不到”。 如果我用'type file.dat'替换file.dat它不会返回(处理器使用率为100%)。 如果我用'find / i'版本替换file.dat:“file.dat”它可以工作,但它非常非常慢(分钟)。因为我必须处理许多文件,而我几乎没有时间使用它。如果我使用查看器手动输入每个文件并复制版本号,它的工作速度会快得多;但重点是我想用cmd做...

哦,我无法在我工作的电脑上安装其他程序....

操作系统是Windows XP x86。

请帮帮我。 谢谢。

最好的问候,Cosmin

稍后编辑: 我已经“构建”了一个测试文件,所以每个人都可以看到并测试:http://www.mediafire.com/download.php?r0x5702lkv14jro 它非常小(真实文件有几十个,有些甚至几百MB)。

稍后编辑:测试文件可用于测试代码是否找到数字,但是,非常小,它不会让您知道实际数据文件需要多长时间。但是你可以这样做:测量扫描测试文件的时间并乘以“100 MB / 2088字节”= 50 219.例如,这与“查找”一起使用。 “类型”甚至更慢(我认为它是指数级的,而不是liniar)。

2 个答案:

答案 0 :(得分:2)

我使用了简化版的jeb FC读取二进制技术来读取DAT文件的前1024个字节。 (converting a binary file to HEX representation using batch file)我只保留可打印的ASCII字符和< LF>,其余的我扔掉了。我使用了一个包含1024< backspace>的比较文件因此我不必担心FC输出中的间隙。

我使用我为hexDump.bat例程(http://www.dostips.com/forum/viewtopic.php?p=7038)开发的地图将十六进制表示转换回ASCII字符。

然后剩下的就是一些直接的字符串操作来解析版本。我查找<LF>version:,删除前导空格,然后将所有可打印字符提取到下一个<LF>作为版本值。

此解决方案假设版本位于前1024个字符内。只需增加比较文件的大小,就可以扩展它以支持前8k。

解决方案似乎速度很快,DAT文件的大小应该对性能没有影响。

@echo off
setlocal enableDelayedExpansion

:: Build a binary file containing 1024 <backSpace> characters
set compareFile="BS1024.DAT"
if not exist %compareFile% (
  for /f "tokens=1 delims=# " %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
    <nul set/p"=%%a" >%compareFile%
  )
  for /l %%n in (1 1 10) do type %compareFile% >>%compareFile%
)

:: Create a variable containing <lineFeed> character (0x0A)
set lf=^


:: Above 2 blank lines are critical - do not remove.

:: Grab the first 1024 bytes, preserving only printable ASCII characters and <lineFeed>
set map= ^^^!^"#$%%^&'^(^)*+,-./0123456789:;^<=^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^^^_`abcdefghijklmnopqrstuvwxyz{^|}~
set datFile="test.dat"
set "dat="
for /f "eol=F usebackq tokens=2 skip=1 delims=:[] " %%A in (`fc /b %datFile% %compareFile%`) do (
  if "%%A"=="0A" (set "dat=!dat!!lf!") else (
    set /a "n=0x%%A-32"
    if !n! geq 0 if !n! leq 94 for %%n in (!n!) do set "dat=!dat!!map:~%%n,1!"
  )
)

:: Find the version line and get the value
set "version="
for %%C in ("!lf!") do set "dat2=!dat:*%%~Cversion:=!"
if "!dat2!" neq "!dat!" (
  for /f "tokens=* eol= delims= " %%A in ("!dat2!") do (
    set "version=%%A"
    goto :done
  )
)
:done
set version

答案 1 :(得分:0)

如果“版本”前面有二进制数据,则您的IF无法正常工作 因为%% A的内容类似于“{binary} version:”

尝试一下,测试字符串“version”是否在行中的任何位置。 如果你有 ”!”在您的二进制数据中,它可能会失败,然后解决方案必须是拉皮条。

setlocal EnableDelayedExpansion
for /f "tokens=* delims=" %%A in ('type file.dat') do (
    set "line=%%A"
    set "version=!line:*version=!"
    if "!line!" NEQ "!version!" (
        goto found
    )
)
echo not found
goto end
:found
echo found: %version%
:end

编辑:

for /f "tokens=* delims=" %%A in (file.dat) do (...

在正常的for循环中,主要问题是十六进制代码0x00,因为它在一行中找到,文件读取立即停止。

类型更多可以抑制此情况。