Solved

# How to write a "mainframe" of "binary" style txt file in VBScript

Posted on 2009-05-05
766 Views
Well folks, this is a continuation of a case that I'm having here and it deserves it own question for sure. I'm not an expert in Vbscript and I'm try to make one to process some txt files that come from a Healthcare Mainframe. Let me show you a basic example of what is my problem. I have attached 2 files. The first one is an example copy directly form the mainframe and the second is an output from my script above. I know that the problem relies on the way I'm reading or writing the file. Is there a way to manipulate this kind of text files by looking for something on it, write some stuff after that, and closing the file with the same format?
How can I make this work so the output is the same binary wise?
HINT: Put some watches on the different strlines and you will see what I'm talking about ;P

'Test Script

Const intForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set SecondobjFSO = CreateObject("Scripting.FileSystemObject")

strFolder = "C:\VBScriptstest\"
Set objFldr = objFSO.GetFolder(strFolder)

x = 0
For Each objFile In objFldr.Files
strinputfile = strFolder & objFile.Name

Set objInputFile = objFSO.OpenTextFile(strinputfile, intForReading, False)
Set objlines = CreateObject("System.Collections.ArrayList")
While Not objInputFile.AtEndOfStream
Wend
objInputFile.Close
Set objInputFile = Nothing
strOutputFile = strFolder & "Processed\" & objFile.Name
If Not objFSO.FolderExists("C:\VBScriptstest\Processed") Then
Set newfolder = objFSO.CreateFolder("C:\VBScriptstest\Processed")
End If
Set objOutputFile = objFSO.CreateTextFile(strOutputFile, intForWriting, True)
For Each objLine In objlines
objOutputFile.WriteLine objLine
Next
objOutputFile.Close
Set objOutputFile = Nothing

strinputfile = strOutputFile
Set objSecondInputFile = SecondobjFSO.OpenTextFile(strinputfile, intForReading, False)
Set Secondobjlines = CreateObject("System.Collections.ArrayList")
While Not objSecondInputFile.AtEndOfStream
Wend
objSecondInputFile.Close
Set objInputFile = Nothing
Set objSecondOutputFile = SecondobjFSO.CreateTextFile(strOutputFile, intForWriting, True)
For Each SecondobjLine In Secondobjlines
objSecondOutputFile.WriteLine SecondobjLine
Next
objSecondOutputFile.Close
Set objSecondOutputFile = Nothing
Next

MsgBox "Done"

VBScriptstest.zip
0
Question by:angelarmando
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• 14
• 11

LVL 12

Expert Comment

ID: 24310616
You need to be reading and writing the file in binary

an excellent example

snippet below

zf

' This is a simple example of managing binary files in
' vbscript using the ADODB object
dim inStream,outStream

' We can create the scream object directly, it does not
' need to be built from a record set or anything like that

' We call open on the stream with no arguments.  This makes
' the stream become an empty container which can be then
' used for what operations we want
inStream.Open

' Now we load a really BIG file.  This should show if the object
' reads the whole file at once or just attaches to the file on
' disk
' You must change this path to something on your computer!inStream.LoadFromFile("d:\Documents and Settings\aturner\Desktop\ScriptingDel\TestData\test.jpg")

' Copy the dat over to a stream for outputting
outStream.Open

dim buff

' Write out to a file
outStream.Write(buff)
' You must change this path to something on your computer!
outStream.SaveToFile("d:\Documents and Settings\aturner\Desktop\ScriptingDel\TestData\test_out.jpg")

outStream.Close()
inStream.Close()

0

Author Comment

ID: 24314912
Hey zoofan,
THANK YOU!
That works as a charm. Thanks! Now, with that reading method, do I loose all the capabilities to modify the txt file data like adding some lines depending on the content or deleting another ones? I'm asking because I have a version of what I want just using CreateObject("Scripting.FileSystemObject") but is giving me the "squares with text" kind of output...
0

LVL 12

Expert Comment

ID: 24315056
Once you read the the binary stream if you want to modify it you would have to modify the stream(in binary) and then write the output.

It is not that you per say loose the ability but it changes what how you do it.

A few options:
You can read all the data in as a string, modify what you want and then convert the entire string to a binary stream for writing.

Convert what you want to add in to a binary stream, Read the data in as a binary stream adding your data to the stream where needed then write the combined stream to a new file.

a few examples:
http://www.motobit.com/tips/detpg_BinASP/
(see Function Stream_StringToBinary)

zf

0

Author Comment

ID: 24315580
Thanks zf,

Did just opened a new world of file manipulation for me ;P
I saw the examples and they look good. But I don't know when to start. Can you help me?
I just atached two files. The second one "_OUT" contains and example of what I'm trying to do. So if we dump the binary read to a string, how do we look for the specific line of tex to insert my additionals lines?
So if we are looking for something like this:
"XXXXXXXXXXXXXXXXXXXXXXXXX999999999999 X     XXXXXXXX XXXXXXXX 999"
to insert something like this afterwards:
"*************************************************************************************
*NEW                                                                                                        *
*TEXT                                                                                                       *
*BLOCK                                                                                                    *
*************************************************************************************
How can we do it?
' This is a simple example of managing binary files in
' vbscript using the ADODB object
dim inStream,outStream

' We can create the scream object directly, it does not
' need to be built from a record set or anything like that

' We call open on the stream with no arguments.  This makes
' the stream become an empty container which can be then
' used for what operations we want
inStream.Open

' Now we load a really BIG file.  This should show if the object
' reads the whole file at once or just attaches to the file on
' disk

' Copy the dat over to a stream for outputting
outStream.Open

dim buff

' Write out to a file
outStream.Write(buff)

outStream.SaveToFile("C:\VBScriptstest\AAUDTBGC_U510_20090429_0000_OUT.txt")

outStream.Close()
inStream.Close()

msgbox "Done"

VBScriptstest.zip
0

LVL 12

Expert Comment

ID: 24315657
Have the files, will look at them and get back with you.  Might be a little bit (at work:-) but will do.

Question is the string your looking for always the same or different? if different how to want to go about entering it? input box or manually edit the script?

zf

0

Author Comment

ID: 24316244
It's diferent....The script will look inside a buch of folders and every folder contains a collection of files. The "line to look" is different per folder but I had that take care of in code already by some variables. I just need some help inserting the Text block after a specific line an delete the same amount of lines after it. So if the text block is 5 lines, we have to delete 5 lines after the insert. I will be sure that those lines are empty ;P

Hey man sorry if this is a big task but any help is appreciated. I just want to learn for next time...

angelarmando
0

LVL 12

Expert Comment

ID: 24316413
no problem sadly I enjoy it :-) ,  glad you mentioned you need to delete the equal amout you add.  will work with and get back to you.

zf
0

LVL 12

Expert Comment

ID: 24318800
Quick question, you are looking to only replace the exact number of lines after the found line, correct?

not file size match in bytes (replacing line by line will change file size if bytes of new lines is less/more than bytes of old line)

zf
0

Author Comment

ID: 24319015
Right. The idea runs like this:

Open the input file
Read the file line by line
Close the input line (I guess)
Look for an specific line
Insert some specific lines of text from a variable right after
Delete the same amount of lines inserted just after the insertion
Create an outputfile in a subdirectory
Write the modified file in memory
Close it

What do you think?
0

LVL 12

Accepted Solution

zoofan earned 500 total points
ID: 24319103
Give this a try :-)
this is rough draft script to give you the idea and something to work with

Edit lines where noted

zf
Option Explicit
Dim objFSO
Dim objInputFile
Dim objOutputFile
Dim arrFileLines()
Dim intLineCount
Dim strInputFIle
Dim strOutputFile
Dim strSearchLine
Dim intLineLoop
Dim intNewloop

Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

'Edit to input/output filename
strInputFIle = "C:\in.txt"
strOutputFile = "C:\out.txt"

'Edit to EXACT line to search for including preceding spaces, case sensitive
strSearchLine = "  XXXXXXXXXXXXXXXXXXXXXXXXX999999999999 X     XXXXXXXX XXXXXXXX 999"

'Edit the number of elements in the array to the number of lines to replace 5 in this example (array is zero based)

'Edit add or remove lines here matching array elements number set above (array is zero based)
arrLinesToAdd(3) = "*                                      OF TEXT                                      *"

Set objFSO = CreateObject("Scripting.FileSystemObject")

intLineCount = 0

'Open and read the file line by line into arrFileLines test for our search line and store the line number
Do Until objInputFile.AtEndOfStream
ReDim Preserve arrFileLines(intLineCount + 1)
If strSearchLine = arrFileLines(intLineCount) Then intLinetoAddAfter = intLineCount
intLineCount = intLineCount + 1
Loop
objInputFile.Close
Set objInputFile = Nothing

'If we found our line then write the new file

Set objOutputFile = objFSO.OpenTextFile (strOutputFile,ForWriting,True,TristateUseDefault)
For intLineLoop = 0 To intLineCount - 1
If intLineLoop  = intLinetoAddAfter +1 Then
intLineLoop = intLineLoop + 1
Next
intLineLoop = intLineLoop - 1
Else
If intLineLoop <> intLineCount - 1 Then
objOutputFile.Writeline arrFileLines(intLineLoop)
Else
objOutputFile.Write arrFileLines(intLineLoop)
End If
End if
Next
objOutputFile.Close
WScript.Quit(0)
Else
WScript.Quit(0)
End If

0

Author Comment

ID: 24319371
Dude! this looks awesome!!
Let me take a detailed look at it tonight..
I ran some tests and is doing his work...
I got like 10 questions already to unsderstand the way like you read the file...
Great stuff!
Talk to you soon.... :P
0

Author Closing Comment

ID: 31578227
0

LVL 12

Expert Comment

ID: 24319410
Doing a line replace meant not actually having to do a binary read and write and made it much easier to deal with,  glad it works for you.

zf
0

Author Comment

ID: 24329607
Hey zf,

I like you search system. Pretty clever. I'm getting some results! But of course I want to tweak it more. What if my strSearchLine repeats every often inside my file? Like some kind header? For example, in my case I'm looking for an specific line inside the file that contains "Page 1". So if you follow the logic, I'm looking to insert the text just before that line. So if my report (text file) contains 15 patients, I will have 15 "Page 1" lines. So the way is set up right now is to set the intLinetoAddAfter = intLineCount when it finds "Page 1". But only works in the last patient (Makes sense since intLinetoAddAfter will get overwritten).

So I have an idea:
How about setting that intLinetoAddAfter to a arrLinetoAddAfter that holds all the values of the lines to go and insert? How do I set that here?:

Do Until objInputFile.AtEndOfStream
ReDim Preserve arrFileLines(intLineCount + 1)
If strSearchLine = arrFileLines(intLineCount) Then intLinetoAddAfter = intLineCount
intLineCount = intLineCount + 1
Loop

and here?:

For intLineLoop = 0 To intLineCount - 1
If intLineLoop = intLinetoAddAfter + 1 Then
intLineLoop = intLineLoop + 1
Next
intLineLoop = intLineLoop - 1
Else
If intLineLoop <> intLineCount - 1 Then
objOutputFile.Writeline arrFileLines(intLineLoop)
Else
objOutputFile.Write arrFileLines(intLineLoop)
End If
End If
Next

Thanks a million zf ;P
0

LVL 12

Expert Comment

ID: 24329634
So each file has more than one place to replace lines? like a file with 10 patients your search string appears 10 times and you need to do a replace on all ten?  trying to make sure I understand

zf
0

Author Comment

ID: 24329755
Ok. Imaging a report (txt) that is pretty user firendly.
It formatted like this:
TEST PAGE (we will ignored)
Patient 1Headers(First strSearchLine match will be there(PAGE 1 for example).
Details (With page numbers)
Totals (Footers)
Details (With page numbers)
Totals (Footers)

and so and so....

Is working because if I got the last patient, the insertion is there. I think that we just have to have and array to store all those insertion matches (lines numbers) and then write and pause and insert when we hit one of them.. Does this makes sense?
0

LVL 12

Expert Comment

ID: 24329784
yes,

working on it now, brb

zf
0

LVL 12

Expert Comment

ID: 24329932
try this,

searches for each occurrence of the search string stores the line numbers as #,#,#,#

splits the return into an array and does a replace at each rebuilding the file.

zf
Option Explicit
Dim objFSO
Dim objInputFile
Dim objOutputFile
Dim arrFileLines()
Dim intLineCount
Dim strInputFIle
Dim strOutputFile
Dim strSearchLine
Dim intLineLoop
Dim intNewloop
Dim arrLineNums
Dim intTempHoler
Dim bolThisline
Dim intLine

Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

'Edit to input/output filename
strInputFIle = "c:\in.txt"
strOutputFile = "c:\out.txt"

'Edit to EXACT line to search for including preceding spaces, case sensitive
strSearchLine = "  XXXXXXXXXXXXXXXXXXXXXXXXX999999999999 X     XXXXXXXX XXXXXXXX 999"

'Edit the number of elements in the array to the number of lines to replace 5 in this example (array is zero based)

'Edit add or remove lines here matching array elements number set above (array is zero based)
arrLinesToAdd(3) = "*                                      OF TEXT                                      *"

Set objFSO = CreateObject("Scripting.FileSystemObject")

intLineCount = 0

'Open and read the file line by line into arrFileLines test for our search line and store the line number
Do Until objInputFile.AtEndOfStream
ReDim Preserve arrFileLines(intLineCount + 1)
If strSearchLine = arrFileLines(intLineCount) Then
intTempHoler = intLineCount + 1
End If
intLineCount = intLineCount + 1
Loop
objInputFile.Close
Set objInputFile = Nothing
bolThisline = False
'If we found our line then write the new file
Set objOutputFile = objFSO.OpenTextFile (strOutputFile,ForWriting,True,TristateUseDefault)
For intLineLoop = 0 To intLineCount - 1
For Each intLine In arrLineNums
If cstr(intLine) = cstr(intLineLoop) Then
bolThisline = True
Exit For
Else
bolThisline = False
End if
Next
If bolThisline = True Then
bolThisline = False
intLineLoop = intLineLoop + 1
Next
intLineLoop = intLineLoop - 1
Else
If intLineLoop <> intLineCount - 1 Then
objOutputFile.Writeline arrFileLines(intLineLoop)
Else
objOutputFile.Write arrFileLines(intLineLoop)
End If
End If
Next
objOutputFile.Close
WScript.Quit(0)
Else
WScript.Quit(0)
End If

0

Author Comment

ID: 24330022
Wow.... you just make it look so easy. Let me try it out! I'm sure it will work ;P
BTW, I was working in a solution too... I will implement yours of course but I will post mine so you can give me your opinion. It will be an very valuable to me :)
0

LVL 12

Expert Comment

ID: 24330284
lol, thanks but I'm a novice at best.

Learning my way thru it, come here to get ideas and problems to solve from others.

Its an unlimited supply of real world problems that aren't my headache :-)  and most I would never come across in my environment, kinda like my leaning aid...

will gladly look at what you have as well.

zf
0

Author Comment

ID: 24330905
Alright my friend! I got a posible solution using the arrLinetoAddAfter. (I still gona use yours ;P)
To read and Identify the lines:

Set objInputFile = objFSO.OpenTextFile(strInputFIle, ForReading, False, TristateUseDefault)

'Reset Counters
intLineCount = 0
intAfterCounter = 0

'Read the file line by line into arrFileLines test for our search line and store the line number
Do Until objInputFile.AtEndOfStream
ReDim Preserve arrFileLines(intLineCount + 1)
If strSearchLine = arrFileLines(intLineCount) Then
intAfterCounter = intAfterCounter + 1
End If
intLineCount = intLineCount + 1
Loop
objInputFile.Close
Set objInputFile = Nothing
'If we found our lines then write the new file
Set objOutputFile = objFSO.OpenTextFile(strOutputFile, ForWriting, True, TristateUseDefault)
intPosition = 0
For intLineLoop = 0 To intLineCount - 1
intPosition = intPosition + 1
End If
intLineLoop = intLineLoop + 1
Next
intLineLoop = intLineLoop - 1
Else
If intLineLoop <> intLineCount - 1 Then
objOutputFile.Writeline arrFileLines(intLineLoop)
Else
objOutputFile.Write arrFileLines(intLineLoop)
End If
End If
Next
objOutputFile.Close
End If

0

LVL 12

Expert Comment

ID: 24331291
Great job!!

only found two things noted both below in snippet.

very well done!  more than one way to skin a cat!!  and btw your code is more efficient as you removed the need for an additional for/next loop that I had in mine.

Use yours!!!!

zf

Set objInputFile = objFSO.OpenTextFile(strInputFIle, ForReading, False, TristateUseDefault)

'Reset Counters
intLineCount = 0
'Erase arrLinetoAddAfter() 											'Removed this line dont need it as we reDim on next line(redim without preserve erases the array)
intAfterCounter = 0

'Read the file line by line into arrFileLines test for our search line and store the line number
Do Until objInputFile.AtEndOfStream
ReDim Preserve arrFileLines(intLineCount + 1)
If strSearchLine = arrFileLines(intLineCount) Then
arrLinetoAddAfter(intAfterCounter) = intLineCount + 1 	'need to add 1 to this to get the correct line number (we want to start our replace on the line after we find our string)
intAfterCounter = intAfterCounter + 1
End If
intLineCount = intLineCount + 1
Loop
objInputFile.Close
Set objInputFile = Nothing
'If we found our lines then write the new file
Set objOutputFile = objFSO.OpenTextFile(strOutputFile, ForWriting, True, TristateUseDefault)
intPosition = 0
For intLineLoop = 0 To intLineCount - 1
intPosition = intPosition + 1
End If
intLineLoop = intLineLoop + 1
Next
intLineLoop = intLineLoop - 1
Else
If intLineLoop <> intLineCount - 1 Then
objOutputFile.Writeline arrFileLines(intLineLoop)
Else
objOutputFile.Write arrFileLines(intLineLoop)
End If
End If
Next
objOutputFile.Close
End If

0

LVL 12

Expert Comment

ID: 24331311
Is a nice change of pace to see one trying to not only solve their problems but learn from them, many want only for made-to order solutions and move on.

Thank you for reminding me why I love this site.....

zf
0

LVL 12

Expert Comment

ID: 24331465
Just in case that cat has a tiny bit of hair left :-)  you inspired me to rewrite the orginal

see below,  now were cooking!!!!! with 45% less code

zf
Option Explicit
Dim objFSO
Dim objInputFile
Dim objOutputFile
Dim strFileLine
Dim strInputFIle
Dim strOutputFile
Dim strSearchLine
Dim intNewloop
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

'Edit to input/output filename
strInputFIle = "M:\VBScriptstest\in.txt"
strOutputFile = "M:\VBScriptstest\out.txt"

'Edit to EXACT line to search for including preceding spaces, case sensitive
strSearchLine = "  XXXXXXXXXXXXXXXXXXXXXXXXX999999999999 X     XXXXXXXX XXXXXXXX 999"

'Edit the number of elements in the array to the number of lines to replace 5 in this example (array is zero based)

'Edit add or remove lines here matching array elements number set above (array is zero based)
arrLinesToAdd(3) = "*                                      OF TEXT                                      *"

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objOutputFile = objFSO.OpenTextFile (strOutputFile,ForWriting,True,TristateUseDefault)

Do Until objInputFile.AtEndOfStream
If strSearchLine = strFileLine Then
objOutputFile.Writeline strFileLine
Next
End If
If objInputFile.AtEndOfStream Then
objOutputFile.Write strFileLine
Else
objOutputFile.Writeline strFileLine
End If
Loop
objInputFile.Close
Set objInputFile = Nothing
objOutputFile.Close
Set objOutputFile = Nothing
WScript.Quit(0)

0

Author Comment

ID: 24335668
Nicely done. I'm glad that you like it. Hey, I'm here to learn dude from all of you. I will keep you in my contacts.

Thanks for everything!

Now, I will keep modifying it to make a final version.

BTW, I'm learning VB.NET 2008 too so this site might give me some ideas ;P
(My VB6 is a little rusty!)
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Over the years I have built up my own little library of code snippets that I refer to when programming or writing a script.  Many of these have come from the web or adaptations from snippets I find on the Web.  Periodically I add to them when I come…
Not long ago I saw a question in the VB Script forum that I thought would not take much time. You can read that question (Question ID  (http://www.experts-exchange.com/Programming/Languages/Visual_Basic/VB_Script/Q_28455246.html)28455246) Here (http…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
###### Suggested Courses
Course of the Month7 days, 15 hours left to enroll