JS/VBS配合Adodb.Stream处理字节数据/输出二进制文件
2010-06-30 14:25
549 查看
一开始,我曾想到将字节数据转换为JS字符串,每两个字节一组转换为一个字节,然后写入类型为文本、编码为“Unicode”的Adodb.Stream对象。
这样做有下面这些问题,但各有方法解决:
首先,将字节数据转换为双字节字符必须要考虑高低位字节顺序(Byte Order)的问题。关系到JS字符串字节顺序的到底是硬件还是软件,目前我还无从得知。不过在目前一般Windows的IE/JScript 5.7中,JS字符串是高位在前低位在后(little endian)。解决方法:在字节对转换成字符前,先将高低字节数据调换。
其次,当字节数据的长度为奇数时,必然存在最后不够凑齐一对字节转换为字符的问题。解决方法:可以先在数据尾部任意补充一个字节,待数据写入Stream对象之后,再将Stream对象转换为二进制类型并移除最后一个字节。
再者,Adodb.Stream在的编码为Unicode时,会自动在文本流的开始位置加入两个字节的BOM(Byte Order Mark)。解决方法:将已经写入数据的Stream类型转换为二进制,此时从第3个字节起读出的所有数据即为我们需要的数据。
后来,我想如果用貌似与Adodb.Stream兼容性更好的VBS来实现,是否可以大大精简代码?
于是我想先试试,通过朝Stream中写入单字节数据的方法是否可行。
可惜经过实践发现,作为VB阉割版的VBS也不能直接支持字节数组的创建,要想往Stream中写入自定义的数据,还是得通过字符串文本。
那么再试试往编码为“iso8859-1”的Stream中写入“单字节字符”,结果ChrB()函数返回的单字节值写不进去,而Chr()函数对大于127的数据不能正确处理。
最后发现,ChrW()能正确处理0~255的数据并写入编码为“iso8859-1”的Stream中。实际写入的只有低字节,高位0均被舍弃。
而且这么做还省去了处理字节顺序和BOM的问题。
进一步推断,其实VBS的ChrW()就相当于JS的fromCharCode(),所以在JS中也能直接用这种更简单的方式来处理
注意:Adodb.Stream对象的类型要设为文本(2),字符集要设为“iso8859-1”,同时待写入字符的高字节必须为0。
PS:可能是由于之前看过一些使用JS对数据进行编码的源码后,某些印象先入为主,一遇到JS处理二进制数据的问题,就首先想到要使用一个字符表示两个字节的数据。现在放开思路,其实完全可以让一个字符只表示单个字节的数据,只不过高字节的0舍弃不用罢了,这样一来代码将可以大大精简。
至于运行效率问题,内存消耗可能会扩大一倍,但是省却了许多的字节调换处理,在数据量规模不太大的情况下,也应该影响不大,最终还是要受制于脚本引擎自身的效率。
这样做有下面这些问题,但各有方法解决:
首先,将字节数据转换为双字节字符必须要考虑高低位字节顺序(Byte Order)的问题。关系到JS字符串字节顺序的到底是硬件还是软件,目前我还无从得知。不过在目前一般Windows的IE/JScript 5.7中,JS字符串是高位在前低位在后(little endian)。解决方法:在字节对转换成字符前,先将高低字节数据调换。
其次,当字节数据的长度为奇数时,必然存在最后不够凑齐一对字节转换为字符的问题。解决方法:可以先在数据尾部任意补充一个字节,待数据写入Stream对象之后,再将Stream对象转换为二进制类型并移除最后一个字节。
再者,Adodb.Stream在的编码为Unicode时,会自动在文本流的开始位置加入两个字节的BOM(Byte Order Mark)。解决方法:将已经写入数据的Stream类型转换为二进制,此时从第3个字节起读出的所有数据即为我们需要的数据。
// 两种生成字符串的方法任选其一 function getDataString() { var s = ''; for (var i = 0; i < 0x100; i++,i++) { s += String.fromCharCode((i+1 << 8) + i); } return s; } function getDataString() { var a = []; for (var i = 0; i < 0x100; i++,i++) { a.push((i+1 << 8) + i); } return String.fromCharCode.apply(null, a); } var s = getDataString(); var stream = new ActiveXObject('Adodb.Stream'); stream.Mode = 3; stream.Open(); stream.Type = 2; stream.Charset = 'unicode'; stream.WriteText(s); stream.Position = 0; stream.Type = 1; stream.Position = 2; var bs = stream.Read(); stream.Position = 0; stream.Write(bs); stream.SetEOS(); stream.SaveToFile('256bytes.bin'); stream.Close();
后来,我想如果用貌似与Adodb.Stream兼容性更好的VBS来实现,是否可以大大精简代码?
于是我想先试试,通过朝Stream中写入单字节数据的方法是否可行。
可惜经过实践发现,作为VB阉割版的VBS也不能直接支持字节数组的创建,要想往Stream中写入自定义的数据,还是得通过字符串文本。
那么再试试往编码为“iso8859-1”的Stream中写入“单字节字符”,结果ChrB()函数返回的单字节值写不进去,而Chr()函数对大于127的数据不能正确处理。
最后发现,ChrW()能正确处理0~255的数据并写入编码为“iso8859-1”的Stream中。实际写入的只有低字节,高位0均被舍弃。
而且这么做还省去了处理字节顺序和BOM的问题。
Dim i, stream Set stream = CreateObject("Adodb.Stream") stream.Mode = 3 stream.Open stream.Type = 2 stream.Charset = "iso8859-1" For i = 0 To 256 - 1 stream.WriteText ChrW(i) Next stream.SaveToFile "256bytes.bin" stream.Close
进一步推断,其实VBS的ChrW()就相当于JS的fromCharCode(),所以在JS中也能直接用这种更简单的方式来处理
var a = []; for (var i = 0; i < 0x100; i++) { a.push(i); } var s = String.fromCharCode.apply(null, a); var stream = new ActiveXObject('Adodb.Stream'); stream.Mode = 3; stream.Open(); stream.Type = 2; stream.Charset = 'iso8859-1'; stream.WriteText(s); stream.SaveToFile('256bytes.bin'); stream.Close();
注意:Adodb.Stream对象的类型要设为文本(2),字符集要设为“iso8859-1”,同时待写入字符的高字节必须为0。
PS:可能是由于之前看过一些使用JS对数据进行编码的源码后,某些印象先入为主,一遇到JS处理二进制数据的问题,就首先想到要使用一个字符表示两个字节的数据。现在放开思路,其实完全可以让一个字符只表示单个字节的数据,只不过高字节的0舍弃不用罢了,这样一来代码将可以大大精简。
至于运行效率问题,内存消耗可能会扩大一倍,但是省却了许多的字节调换处理,在数据量规模不太大的情况下,也应该影响不大,最终还是要受制于脚本引擎自身的效率。
相关文章推荐
- ofstream文件输出流把二进制数据写入文件
- Adodb.Stream是ADO的Stream对象,提供存取二进制数据或者文本流,从而实现对流的读、写和管理等操作.
- 文件操作:输出文件二进制数据
- Adodb.Stream是ADO的Stream对象,提供存取二进制数据或者文本流,从而实现对流的读、写和管理等操作.
- 使用ADODB.Stream对象读二进制文件
- 通过ADO.NET把文件数据导入到数据库(数据的导入导出)stream文件的处理
- ms js利用ado.stream+msxml进行二进制读文件转base64字符输出与反转(提供工具)
- js:读写二进制变通方法,需要有权限控制adodb.stream,可以配合hta使用
- 将图像等文件转为二进制数据再输出实现复制
- 第4章 处理用户输入与显示数据------------(禁止命令输出、lsof命令、关闭文件描述符、创建读取/写入文件描述符)
- 用JAVA处理文本与二进制数据混合大文件
- spring mvc源码-》MultipartReques类-》主要是对文件上传进行的处理,在上传文件时,编码格式为enctype="multipart/form-data"格式,以二进制形式提交数据,提交方式为post方式。
- 向文件输出数据的输出字节流
- 将文件input.bin中的数据按字节(无符号数值)统计,输出每个数值在文件中出现的次数
- 利用JDBC处理mysql大数据--大文本和二进制文件等
- C++中的文件输入/输出(5):二进制文件的处理
- vb 遍历sheet名和对数据循环处理并输出到文件
- 关于Adodb.Stream的写数据库数据到客户端文件的实践
- 这个C++程序 输入一组数据 为何会输出很多个结果啊~ 是有关文件处理的