在VBScript中读写二进制文件

15

我曾使用ADODB.Stream读写二进制文件,这是链接:

如何在VBScript中使用ADODB.stream连接二进制文件

它能正常工作,但唯一的问题是Windows 2003服务器上禁用了ADODB.stream。

是否有另一种方法可以在VBScript中以二进制模式读取3个文件并将它们连接或存储到一个文件中?

谢谢
Jp

6个回答

6

I had a similar problem a year ago. We know that the TextStream objects are intended for ANSI or Unicode text data, not binary data; their .readAll() method produces a corrupted output if the stream is binary. But there is workaround. Reading the characters one by one into an array works fine. This should allow you to read binary data into VB strings, and write it back to disk. When further manipulating such binary strings do not forget that certain operations may result into broken strings because they are intended for text only. I for one always convert binary strings into integer arrays before working with them.

Function readBinary(path)
Dim a
Dim fso
Dim file
Dim i
Dim ts
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.getFile(path)
If isNull(file) Then
    MsgBox("File not found: " & path)
    Exit Function
End If
Set ts = file.OpenAsTextStream()
a = makeArray(file.size)
i = 0
' Do not replace the following block by readBinary = by ts.readAll(), it would result in broken output, because that method is not intended for binary data 
While Not ts.atEndOfStream
    a(i) = ts.read(1)
i = i + 1
Wend
ts.close
readBinary = Join(a,"")
End Function

Sub writeBinary(bstr, path) Dim fso Dim ts Set fso = CreateObject("Scripting.FileSystemObject") On Error Resume Next Set ts = fso.createTextFile(path) If Err.number <> 0 Then MsgBox(Err.message) Exit Sub End If On Error GoTo 0 ts.Write(bstr) ts.Close End Sub

Function makeArray(n) ' 这是一个小工具函数 Dim s s = Space(n) makeArray = Split(s," ") End Function


1
这种解决方法并不是一个好的实践。它不能适用于所有的代码页。你真的在处理一个边缘情况,我不会把它投入生产。 - Nilpo

6

基于Luc125和Alberto的回答,这里是两个重新设计和简化的函数:

读取函数

Function readBinary(strPath)

    Dim oFSO: Set oFSO = CreateObject("Scripting.FileSystemObject")
    Dim oFile: Set oFile = oFSO.GetFile(strPath)

    If IsNull(oFile) Then MsgBox("File not found: " & strPath) : Exit Function

    With oFile.OpenAsTextStream()
        readBinary = .Read(oFile.Size)
        .Close
    End With

End Function

写函数
Function writeBinary(strBinary, strPath)

    Dim oFSO: Set oFSO = CreateObject("Scripting.FileSystemObject")

    ' below lines pupose: checks that write access is possible!
    Dim oTxtStream

    On Error Resume Next
    Set oTxtStream = oFSO.createTextFile(strPath)

    If Err.number <> 0 Then MsgBox(Err.message) : Exit Function
    On Error GoTo 0

    Set oTxtStream = Nothing
    ' end check of write access

    With oFSO.createTextFile(strPath)
        .Write(strBinary)
        .Close
    End With

End Function

你需要这行代码吗?Dim oTxtStream: Set oTxtStream = oFSO.createTextFile(strPath) - Sen Jacob
1
那行代码应该是用来检查文件写入权限的。如果你把它删除了,在某些情况下脚本可能会崩溃。 - n3rd4i
1
虽然这种方法有时可以工作,但通常是一种不好的做法。FSO 设计用于标准文本流的使用。这种解决方法并非万无一失,在某些环境下会失败。最好坚持使用 ADODB,它是一种专门用于处理二进制流的本地方法。没有额外的开销,而且更有效率。双赢。 - Nilpo

4

ADODB流对象是VBScript读取二进制流的唯一本地方法。如果ADODB被禁用,则需要安装其他第三方组件来提供相同的功能。


不需要安装任何外部程序;仍然可以在没有ADODB的情况下完成;我总是可以在没有它的情况下读/写二进制文件。 - Zimba
2
@Zimba FSO 无法可靠地处理二进制数据。它是为文本流设计的。ADODB 是唯一专为处理二进制数据流而设计的本机方法。 - Nilpo
FileFileSystemObject都可以处理二进制数据。问题是要求“另一种方法”,而不使用ADODB。我已在Win 10上测试了音频、视频、图像、zip归档文件和pdf文件。您的方法仅适用于ADODB,无需外部下载即可运行。 - Zimba

1

可以一次读取所有字节:

Set FS = CreateObject("Scripting.FileSystemObject")
Set fil = FS.GetFile(filename)
fpga = fil.OpenAsTextStream().Read(file.Size)

你的意思是读取(fil.Size)吗? - Zimba
2
FSO 不可靠地处理二进制数据。 - Nilpo
@Nilpo:你为什么只对我的答案投票了呢?你做了哪些测试来支持你的说法? - Zimba
2
.read和.write的行为被认为取决于系统语言环境。在使用EN语言环境的英语国家,它可以可靠地工作。但在其他国家,它可能无法正常工作。 - david
测试了一下简单的PDF文件,但代码对我来说无法工作。同意Nilpo和David的看法,FileSystemObject不能可靠地处理二进制数据。 - Lily Liu

1
ADODB流对象是VBScript中读取二进制流的唯一本地方法。
Const TypeBinary = 1
Const ForReading = 1, ForWriting = 2, ForAppending = 8

Function readBytes(file)

     Dim inStream: Set inStream = WScript.CreateObject("ADODB.Stream") ' ADODB stream object used

     inStream.Open ' open with no arguments makes the stream an empty container 
     inStream.type= TypeBinary
     inStream.LoadFromFile(file)
     readBytes = inStream.Read()

End Function

Sub writeBytes(file, bytes)

    Dim binaryStream: Set binaryStream = CreateObject("ADODB.Stream")

    binaryStream.Type = TypeBinary
    binaryStream.Open 'Open the stream and write binary data
    binaryStream.Write bytes
    binaryStream.SaveToFile file, ForWriting 'Save binary data to disk

End Sub

1

读取3个文件并合并为一个文件(不使用 ADODB):

Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
If oFSO.FileExists("out.bin") Then oFSO.DeleteFile("out.bin")
Dim outFile : Set outFile = oFSO.OpenTextFile("out.bin", 8, true)

' 3 input files to concatenate
Dim oFS1 : Set oFS1 = oFSO.GetFile("in1.bin")
Dim oFS2 : Set oFS2 = oFSO.GetFile("in2.bin")
Dim oFS3 : Set oFS3 = oFSO.GetFile("in3.bin")

Dim read1 : Set read1 = oFS1.OpenAsTextStream()
Dim read2 : Set read2 = oFS2.OpenAsTextStream()
Dim read3 : Set read3 = oFS3.OpenAsTextStream()

Dim write1 : write1 = read1.Read(oFS1.Size)
read1.Close
outFile.write(write1)

Dim write2 : write2 = read2.Read(oFS2.Size)
read2.Close
outFile.write(write2)

Dim write3 : write3 = read3.Read(oFS3.Size)
read3.Close
outFile.write(write3)

outFile.Close

本软件在Win 10上进行了测试,涵盖音频、视频、图像、压缩文件和PDF(二进制文件)的复制、编辑、分割、合并、打补丁以及(字节级)加密、编码和压缩。

有关二进制文件打补丁,请参见此处的示例(答案)


1
本地FSO对象的OpenAsTextStream方法不支持二进制流。它在处理二进制文件时不可靠。 - Nilpo
@Nilpo:当然支持二进制文件;我已经在Win 10上测试了音频、视频、图像、压缩文件和PDF。 - Zimba
1
.read和.write的行为被认为取决于系统语言环境。在使用EN语言环境的英语国家,它可以可靠地工作。但在其他国家,它可能无法正常工作。 - david
@david:fso 可以“编写二进制文件”,但文本字符串函数不会起作用,因为“空值截断字符串”,而二进制数据包含字符串。该问题涉及二进制文件(单字节 ASCII/ANSI 字符),fso 可以处理。由于多字节/Unicode 代码页中缺少代码点来表示其他语言的字符扩展,因此会出现错误。 - Zimba
为了抽象化和本地化映射/检测这些区域设置,开发了一个“高级、易于使用的接口”[ADODB](https://learn.microsoft.com/en-us/sql/ado/guide/ado-introduction?view=sql-server-ver15)。可以使用“GetLocale”和“WMI”(在VBS之后发布)完成。VBScript无法访问本地文件系统。 - Zimba
1
@Zimba。fso是BSTR实现,而不是c字符串实现。空值不会截断BSTR字符串。FSO不会在空值上截断字符串。 - david

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接