本帖最后由 amwfjhh 于 2015-5-19 11:51 编辑
接到一个任务,需要将一些备份资源中的数据导出,其中有许多图片资源与文本描述,而这些图片的编号及其对应的说明则在一个后缀为.db的数据库中,这个数据库有一个专门的应用程序来打开,本想写个脚本来批量完成这事,可是问题来了:如何批量读取数据库里的东西呢?这数据库既不是mysql,也不是sqlserver,更不是PostgreSQL或oracle之类的已知数据库,想调用数据库引擎来读取内容也没法,于是尝试二进制方式读取,用ultraedit打开.db文件,查看它的二进制代码规律,万幸能在其中找到一点蛛丝马迹:
这是它提供的数据库读取程序读出来的内容:
这是ultraedit打开的二进制内容:
可以看到其中规律还是很明显的,数据主体部分应该是用到了一个数据结构体,从其数据库打开程序所看到的关键信息都能在其中找到对应的位置,那我们只需要按照规律读取出来就行了。- 0000080ah: 80 01 D1 AD BB B7 CF B5 CD B3 D5 FD B3 A3 58 CF ; .循环系统正常X?
- 0000081ah: DF B1 ED CF D6 00 00 00 00 00 00 00 00 00 00 00 ; 弑硐?..........
- 0000082ah: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
- 0000083ah: 00 00 00 00 80 03 ; .....
复制代码 这是其中一个结构体的信息,可以看到之后的数字为该条目的编号或者其所拥有的章节数,第一个后的文本部分即为数据表格内容,读取流数据,我们可以用adodb.stream来进行,基于在一个脚本内写完所有内容的要求,我们采用BJ混排的方式,将jscript和bat脚本写到同一个文件里,利用cscript的-e参数可将批处理作为jscript脚本来调用,达到自身既是批处理,也是jscript脚本的目的。但这里面有一个麻烦就是,文本信息是用的中文(或说文本)来存储的,但是编号和拥有章节数这两个数据却不是以文本方式存储的,可以直接将其值以字节的方式存储在二进制文件里面,这对于c或c++之类的语言来说完全没问题,但是对于adodb.stream这个组件来说,它要么吐出字符串,要么吐出字节流,而字节流,在jscript中又无法直接处理,且其获取字符串编码的方式charCodeAt(n)则是直接获取的unicode代码,显示对于直接的字节流支持不是很好,那我们要怎么把这个数据取出来呢,VBScript!虽然有了BJ混排后我极力想将其抛弃,但不得不说,在这里,对于字节流的支持,其leftb,ascb等方法却是救命稻草,能完美解决我的问题,于是方案就出来了,bat调用jscript,创建adodb.stream组件,对文件进行读取,在读取编号时,将文件以流方式读取,再创建一个临时的vbs脚本,用于调用ascb方法,对流编码进行读取,代码如下:- @if (0)==(0) echo off
- setlocal enabledelayedexpansion
-
- REM set /p "strFile=Input binary file:"
- REM set /p "strOffset=Input offset:"
- REM set /p "strLen=Input length of data:"
-
- set "strFile=a.db"
- set "strOffset=2059"
- set "strLen=58"
-
- for /l %%i in (0 1 6) do (
- set /a offsetNum=!strOffset!+%%i*!strLen!
- set /a offsetTxt=!offsetNum!+3
- set /a offsetNum1=!offsetNum!+52
- echo,!offsetNum! !offsetTxt! !offsetNum1!
- cscript -nologo -e:jscript %~s0 GetBinNumber "!strFile!" !offsetNum!
- for /f "delims=" %%b in ('cscript -nologo -e:vbscript "$"') do (set "strIndex=%%b") & del /f "$"
- for /f "delims=" %%a in ('cscript -nologo -e:jscript %~s0 GetBinText "!strFile!" !offsetTxt! !strLen!') do (set "strLine=%%a")
- cscript -nologo -e:jscript %~s0 GetBinNumber "!strFile!" !offsetNum1!
- for /f "delims=" %%b in ('cscript -nologo -e:vbscript "$"') do (set "strIndex1=%%b") & del /f "$"
-
- echo,第 !strIndex! 章, !strLine!, 拥有节数 !strIndex1!
- REM pause>nul
- )
-
- pause
- GOTO :EOF
- @end
-
- var fun = WScript.arguments(0);
-
- switch (fun) {
- case "GetBinText":
- CheckArgs(4);
- var fil = WScript.arguments(1);
- var offset = parseInt(WScript.arguments(2));
- var len = parseInt(WScript.arguments(3));
- GetBinText(fil, offset, len);
- break;
-
- case "GetBinNumber":
- CheckArgs(3);
- var fil = WScript.arguments(1);
- var offset = parseInt(WScript.arguments(2));
- GetBinNumber(fil, offset);
- break;
-
- default:break;
- }
-
- function CheckArgs(num){
- if (WScript.arguments.length < num){
- WScript.echo("参数不齐");
- WScript.quit();
- }
- }
-
- function GetBinText(fil, offset, len){
- var stream;
- var strContent;
-
- stream = new ActiveXObject("adodb.stream");
- stream.open();
- stream.loadFromFile(fil);
- stream.type = 2;
- stream.charset = "gb2312";
- stream.position = offset;
- strContent = stream.readText();
- stream.close();
-
- WScript.echo(strContent);
- }
-
- function GetBinNumber(fil, offset){
- var stream, stream1;
-
- stream = new ActiveXObject("adodb.stream");
- stream.open();
- stream.type = 1;
- stream.loadFromFile(fil);
- stream.position = offset;
-
- //输出序号
- var stream1 = new ActiveXObject("adodb.stream");
- stream1.mode = 3;
- stream1.open();
- stream1.type = 2;
- stream1.charset = "gb2312"
- stream1.writeText("WScript.echo ascb(leftb(\"");
- stream1.position = 0;
- stream1.type = 1;
- stream1.position = 25;
- stream1.write(stream.read(1));
- stream1.position = 0;
- stream1.type = 2;
- stream1.position = 26;
- stream1.writeText("\", 1))");
- stream1.saveToFile("$", 2);
- stream1.close();
-
- stream.close();
- }
复制代码 以下为代码运行效果,读出内容与数据无差异
|