15

I used earlier ADODB.Stream to read and to write binary file here is the link for that

How to concatenate binary file using ADODB.stream in VBscript

it works fine the only problem is ADODB.stream is disabled on windows 2003 server,

Is there another way i can read 3 files in binary mode and concatenate them or store them in one file in VBscript

thank you Jp

Community
  • 1
  • 1
jprbest
  • 717
  • 6
  • 15
  • 32

6 Answers6

6

Based on Luc125 and Alberto answers here are the 2 reworked and simplified functions:

The Read function

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

The Write 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
ib11
  • 2,530
  • 3
  • 22
  • 55
n3rd4i
  • 183
  • 1
  • 4
  • Do you need this line? `Dim oTxtStream: Set oTxtStream = oFSO.createTextFile(strPath)` – Sen Jacob Jul 07 '15 at 06:54
  • 1
    that line is suppose to check the files write access. If you remove it, in some cases the script can crash. – n3rd4i Aug 11 '15 at 05:01
  • 1
    While this works some of the time, it is generally a bad practice. The FSO is designed for use with standard text streams. This workaround is not bulletproof and it does fail in certain environments. It's best to stick to ADODB which is a native method designed for handling binary streams. There's no additional overhead and it's more efficient anyway. Win-win. – Nilpo Oct 27 '20 at 14:24
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) ' Small utility function Dim s s = Space(n) makeArray = Split(s," ") End Function

Luc125
  • 5,752
  • 34
  • 35
  • 1
    This workaround is not a good practice. It won't work with all codepages. You're really dealing with an edge case here and I would not put this into production. – Nilpo Oct 27 '20 at 14:21
4

The ADODB stream object is VBScript's only native method of reading binary streams. If ADODB is disabled, you will need to install some other third-party component to provide the same functionality.

Nilpo
  • 4,675
  • 1
  • 25
  • 39
  • No need to install any externals; still can be done without ADODB; I've always read/write binaries without it – Zimba Oct 27 '20 at 10:00
  • 2
    @Zimba The FSO cannot reliably handle binary data. It's designed for text streams. ADODB is the only native method designed for working with binary data streams. – Nilpo Oct 27 '20 at 14:19
  • Both `File` & `FileSystemObject` can process binary data. The question is asking for "another way" without ADODB. I've tested on audio, video, image, zip archives & pdf on Win 10. Your method only works on ADODB without external downloads. – Zimba Oct 27 '20 at 16:24
1

It is possible to read all bytes together:

Set FS = CreateObject("Scripting.FileSystemObject")
Set fil = FS.GetFile(filename)
fpga = fil.OpenAsTextStream().Read(file.Size)
Cellcon
  • 1,245
  • 2
  • 11
  • 27
Alberto
  • 27
  • 1
  • you mean Read(**_fil_**.Size)? – Zimba Oct 25 '20 at 11:17
  • 2
    FSO does not reliably handle binary data. – Nilpo Oct 27 '20 at 14:18
  • @Nilpo: How come you only voted on my answer? And what tests have you done to make your claim? – Zimba Oct 27 '20 at 14:32
  • 2
    The behavior of .read and .write is known to depend on the system locale. It works reliably in anglophone countries using the EN locales. In other countries, it doesn't work. – david Nov 24 '20 at 00:05
  • Tested the code with a simple pdf file and the code didn't work for me. Agreed with Nilpo and David, FileSystemObject does not reliably handle binary data. – Lily Liu Apr 20 '22 at 21:01
1

ADODB stream object is VBScript's only native method of reading binary streams

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
oleggy
  • 11
  • 1
1

Read 3 files & join to one file (without 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

Tested on audio, video, image, zip archives & pdf (binaries) on Win 10 for binary file copy, edit, split, join, patching & (byte level) encryption, encoding & compression.

See example (answer) here for binary file patching.

Zimba
  • 2,854
  • 18
  • 26
  • 1
    The native FSO object's OpenAsTextStream method doesn't support binary streams. It does not work reliably with binary files. – Nilpo Oct 27 '20 at 14:17
  • @Nilpo: of course it supports binaries; I've tested on audio, video, image, zip archives & pdf on Win 10 – Zimba Oct 27 '20 at 14:29
  • 1
    The behavior of .read and .write is known to depend on the system locale. It works reliably in anglophone countries using the EN locales. In other countries, it doesn't work. – david Nov 24 '20 at 00:04
  • @david:fso can "[write binary files](https://groups.google.com/g/microsoft.public.scripting.vbscript/c/h9EGYLaqiU8)" but text string functions won't work because "Nulls truncate strings", and binary data contains strings. The question refers to binary files (single byte ASCII/ANSI characters), which [fso](https://stackoverflow.com/questions/64510544/how-does-vbscript-filesystemobject-encode-characters) can handle. Errors arise from missing codepoints in multi-byte/unicode codepages that are character extensions to cater for other languages. – Zimba Nov 26 '20 at 09:02
  • A "high-level, easy-to-use interface" [ADODB](https://learn.microsoft.com/en-us/sql/ado/guide/ado-introduction?view=sql-server-ver15) was developed for abstraction & locale mapping/detection for these locales (may also be done with `GetLocale` & `WMI` (released after VBS)). VBScript is restricted from local file system access. – Zimba Nov 26 '20 at 09:03
  • 1
    @Zimba. fso is a BSTR implementation, not a c string implementation. Nulls do not truncate BSTR strings. FSO does not truncate strings on Nulls. – david Nov 26 '20 at 23:46