Solved

How do I create a dynamic array in VB6

Posted on 2001-08-16
22
7,554 Views
Last Modified: 2007-11-27
I have an ASCII flat file, which may grow or shrink.  I would like to read each line of data into an array.  What is the most efficient way to get the number of lines (records) in a file and then Dim an array?  This array is used in several different procedures throughout the form.

I have already Opened the file, read in each line and got a count that way, but it is slow.  I've set an upper limit to the file size, but that is risky.

Thanks,

Russ
0
Comment
Question by:RUSS_EMI
  • 6
  • 5
  • 4
  • +4
22 Comments
 
LVL 20

Expert Comment

by:hes
ID: 6394612
Is each record a fixed length, if so try using
recno = Len(Open File #)/length of each record
redim yourarray(recno)
0
 

Author Comment

by:RUSS_EMI
ID: 6394636
Each record isn't fixed in length.
A sample record is as follows;

filename, start_postion, end_postion, repeat

where filename = string
others = long

This is used to play audio files at specific locations within a text file.

Russ
0
 
LVL 3

Expert Comment

by:Bahnass
ID: 6394676
open "FileName" for append as 13:close 13
open "FileName" for inputas 13

type MyType
    filename
    start_postion
    end_postion
    repeat
end type
Dim Myarray() as MyType
' 13 is the file no
do until eof(#13)
    input #13,Myarray(N).filename, _
        Myarray(N).start_postion, _
        Myarray(N).end_postion, Myarray(N).repeat
     N=N+1
    redim preserve Myarray(N) as MyType
loop
close#13
0
 
LVL 2

Expert Comment

by:BozzoCage
ID: 6394677
Why don't you create REAL dynamic array:

Dim a() As String  'or whatever you need
Redim a(0)  'init value

Dim line_count As Long
line_count = 0

'your file reading
While ...
   Line Input #1, a(line_count)  'or whatever you use
   line_count = line_count +1
   Redim Preserve a(line_count)
Wend

instead of line_count you could use UBound(a), but rather store value it returns to some variable instead of calling it many times
0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6394678
Set a good upper limit and if it is about to be exceeded than use the Preserve keyword to ReDim to a larger size.
0
 
LVL 2

Expert Comment

by:BozzoCage
ID: 6394684
Bahnass, you forgot to set initial value for dynamic array with Redim (can't use var until it has at least 1 element)
0
 
LVL 3

Expert Comment

by:Bahnass
ID: 6394689
3 on same minute ??
bye 4 now ;-)
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6394708
Russ:

   1) How big are the files?

   2) Which version of VB are you using?

   3) Just to verify, each line is terminated by Carriage Return and Line Feed characters?

If it isn't too big, then the following routine should work fine:


   Dim sBuff   As String
   Dim aBuff() As String
   Dim hFile   As Integer

   hFile = FreeFile() 'Get next available File Handle
   Open "somefile" For Binary Input As #hFile
   sBuff = Input(LOF(hFile),hFile) 'Read entire file
   Close #hFile
   aBuff() = Split(sBuff, vbCrLf)


aBuff() is now a dynamic array, loaded with the contents of the file.  aBuff(0) contains the first line, aBuff(1) contains the second line, etc.

If you need to know how many lines, then you can simply add one to the Upper Bound of the array:

   LineCount = UBound(aBuff) + 1



-Dennis Borg
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6394709
>2) Which version of VB are you using?

I see you've already told us this in your subject line. :-)
0
 

Author Comment

by:RUSS_EMI
ID: 6394760
BozzoCage,
   Thank you for your suggestion.  I get a compile error saying that the array is already dimensioned.  
The initial Dim statement is in the Declaration section.
The ReDim Preserve statement is in the Form_Load procedure.
As these arrays are referenced thoughout the Form, how do I proceed?

Russ
0
 

Author Comment

by:RUSS_EMI
ID: 6394784
Dennis,
   The file (which may be from 1 to 1000 lines) consists of 4 elements / line -
              filename, start_pos, end_pos, repeat_value.

Each line does end w/ CrLf.

If I use your suggestion, how do I further parse each line, into the different array elements?

Russ
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 2

Accepted Solution

by:
BozzoCage earned 50 total points
ID: 6394838
global:
  Dim a() as string

form_load()
  redim a(0) 'must use standard redim before using redim preserve

sub read_file
  'on each additional line:
  redim preserve a(ubound(a)+1)


You use this array as any other array (in this case as any other global variable).
Only difference is that it doesn't have fixed bounds. For use in "For" sentences, use Ubound(a) like:
for i=0 to ubound(a)


Since you have more values in a line, you could use
type line_type
  filename as string
 ...
end type
dim a() as line_type

how to split line- if you know delimiter, use "Split" function:

dim new_array() as string
dim delimiter as string
delimiter=","
new_array = split(your_line, delimiter)
a(ubound(a)).filename = new_array(0)

read help on Split function in msdn. It splits values from input string and puts them to array. You must use new array for this, then copy values to correct "slots" in main array.
0
 

Author Comment

by:RUSS_EMI
ID: 6394868
BozzoCage,
   Thank you for that definitive answer.  I'll try it and post the points if all is OK, which I think it will.

Russ
0
 
LVL 3

Expert Comment

by:Bahnass
ID: 6394887
BozzoCage
Thanks for Good  Documentation
Sorry I had notime wrote it on the fly n saw many EE answering

Thanks all of U
0
 
LVL 2

Expert Comment

by:BozzoCage
ID: 6394926
Bahnass, sorry for using almost same sample as you did... I just didn't took time to read other comments...
But anyway, it is hard to show some "other" way if there is more or less single standard way.
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6394940
Russ:

>If I use your suggestion, how do I further parse each
>line, into the different array elements?

Given your description of each line, then you would go about it as follows:

(after you've read the file and created the dynamic array as I suggested above)


   Dim Elements() As String

   Elements = Split(aBuff(0),",") 'Split the first line

Element(0) now contains your FileName
Element(1) now contains your Start Pos
Element(2) now contains your End Pos
Element(3) now contains your Repeat Value


I don't know exactly how you need to process this, but if you need to go thru each line sequentially, then you can use a loop such as the following:

   Dim idxLine    As Long
   Dim uB         As Long
   Dim Elements() As String

   ub = UBound(aBuff)
   For idxLine = 0 To ub
      Elements = Split(aBuff(idxLine), ",")
      ' *** now use Elements(0) thru Elements(3) as needed
   Next 'idxLine



-Dennis Borg
0
 
LVL 3

Expert Comment

by:Bahnass
ID: 6394959
BozzoCage
Nice 2 meet U
thanks 4 EE
U reserve Points if that U R Sorry 4
0
 
LVL 14

Expert Comment

by:wsh2
ID: 6394961
Here is a very fast way to persist Tables.

1. Open a Standard.Exe Project.
2. Copy/Paste the following into the Form1 code window.
3. Press F5 to run. After the program completes, press Control-G to View the Debug Immediate window.

I'll leave it up to you to figure out the rest.. I'm going home!!! <lol> and a <smile>.

<----- Code Begin ----->

Option Explicit

Private Type typMyData
   strField As String
   lngField As Long
   intField As Integer
End Type

Private Type typMyFile
   lngCount As Long
   udtData() As typMyData
End Type

Dim m_udtFileGet As typMyFile
Dim m_udtFilePut As typMyFile

Private Sub Form_Load()

'  Build Table and Write
With m_udtFilePut
   ReDim .udtData(10)
   Dim lngIndex As Long
   For lngIndex = LBound(.udtData) To UBound(.udtData)
      With .udtData(lngIndex)
         .strField = String$(lngIndex, "x")
         .lngField = lngIndex
         .intField = lngIndex * 2
      End With
   Next lngIndex
   .lngCount = UBound(.udtData) + 1
End With

'  Write Data
   Dim strFile As String: strFile = "c:\tempwork\TestFile.Dat" ' <-- CHANGE
   Dim lngFile As Long: lngFile = FreeFile
   If Dir(strFile) <> "" Then
      Kill strFile
   End If
   Open strFile For Binary As lngFile
   Put lngFile, , m_udtFilePut
   Close lngFile

'  Read Data
   Open strFile For Binary As lngFile
   Get lngFile, , m_udtFileGet
   Close lngFile
   
'  Display Data In The Immediate Window
With m_udtFileGet
   For lngIndex = LBound(.udtData) To UBound(.udtData)
      With .udtData(lngIndex)
         Debug.Print .strField & " " _
            & .lngField & " " _
            & .intField
      End With
   Next lngIndex
End With

   Unload Me

End Sub

<----- Code End ----->


0
 

Author Comment

by:RUSS_EMI
ID: 6395172
I'm overwhelmed at the various ways to skin this cat.
Still processing the comments to find the best solution.

BozzoCage's suggestion doesn't work, due to the fact I'm using a multi-dimensional array.

I don't fully understand wsh2's suggestion, but give me time.

Am working on Dennis's solution.  Will let you know.

Here is some sample code, does this help understand?

*****************************


Dim X As Integer
Dim sound_number As Integer
Dim picture_number As Integer
Dim mypath
Dim CdKey As String
Dim CdPath As String
Dim BookmarkLocation As Long
Dim BookmarkString As String
Dim cr As CharRange
Dim pict(9) As String
Dim pictloc(9,3) As Long
Dim aud(9) As String
Dim audloc(9,2) As Long
Dim playing(9) As Boolean


Private Sub Form_Load()
If Dir(mypath + "text\sounds.txt") > "" Then
Open mypath + "text\sounds.txt" For Input As #1

X = 0

Do While Not EOF(1) ' Loop until end of file.
            ' sound file, min,        max,          repeat times
   Input #1, aud$(X), audloc(X, 0), audloc(X, 1), audloc(X, 2)
   MP2(X).PlayCount = audloc(X, 2)
   X = X + 1

Loop
sound_number = X - 1

Close #1    ' Close file.

Else
EnableAudio.Visible = False
EnableAudio.Value = 0
End If


If Dir(mypath + "text\pictures.txt") > "" Then

Open mypath + "text\pictures.txt" For Input As #1

X = 0

Do While Not EOF(1) ' Loop until end of file.
            ' picture file, min,        max,            left,           top
   Input #1, pict$(X), pictloc(X, 0), pictloc(X, 1), pictloc(X, 2), pictloc(X, 3)
   Picture1(X).Left = pictloc(X, 2)
   Picture1(X).Top = pictloc(X, 3)
   Set Picture1(X).Picture = LoadPicture(pict$(X))
   X = X + 1

Loop
picture_number = X - 1
Close #1    ' Close file.

Else
EnablePictures.Visible = False
EnablePictures.Value = 0
End If

BookmarkLocation = rtfTest.Find(" ", BookmarkLocation)

Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer()
' get minimum & maximum screen characters within RTF window
cr = GetCharrange(rtfTest)

If (EnableAudio.Value > 0 Or EnablePictures.Value > 0) Then


 If EnableAudio.Value = 1 Then
 
 For X = 0 To sound_number
 If cr.cpMax <= audloc(X, 1) And cr.cpMax >= audloc(X, 0) Then
 If Not playing(X) Then MP2(X).Open (aud$(X))
 playing(X) = True
 Else
 playing(X) = False
 MP2(X).Stop
 End If
 Next
 
 End If
 
 
 
 
 If EnablePictures.Value = 1 Then
 
 For X = 0 To picture_number
 If cr.cpMax <= pictloc(X, 1) And cr.cpMax >= pictloc(X, 0) Then
 Picture1(X).Visible = True
 Else
 Picture1(X).Visible = False
 End If
 Next
 
 End If
 
 
 
End If
 End Sub
************************************************

To all THANKS!

Russ



0
 
LVL 2

Expert Comment

by:BozzoCage
ID: 6396206
You didn't mentioned that you use multi-dimensional array. Well, with ReDim you can resize last dimension only.
0
 

Author Comment

by:RUSS_EMI
ID: 6397151
It is hard to award the points to only 1 response and be fair.  Please understand I got a little more from each answer.  In the program I ended up using all single dimensional arrays.  All seems to work fine.
Again, thank you all for responding.

Russ
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6397222
>It is hard to award the points to only 1 response and be
>fair.  Please understand I got a little more from each
>answer.

You did just fine, Russ. Glad to see you arrived at a working solution! That's the important thing.


-Dennis Borg
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Opening Remote & Local Data Connection 2 41
DIR issue 7 47
using Access 8 52
Exit a vb6 apps when a calling it apps closes 15 35
Introduction I needed to skip over some file processing within a For...Next loop in some old production code and wished that VB (classic) had a statement that would drop down to the end of the current iteration, bypassing the statements that were c…
If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now