Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
11-03-2023, 11:21 PM
(This post was last modified: 11-03-2023, 11:23 PM by PhilOfPerth.)
I need to create a file that I can access randomly, by specifying a record-number
I think this requires an Indexed file, but don't know how to create this.
I would need to access it with something like
Open "myfile" for input as #1
Input #1, RecNum10 (to access the 10th record).
I can do this by reading from the file 10 times, but this would be slow.
Any suggestions?
Posts: 372
Threads: 23
Joined: May 2022
Reputation:
56
I think you can use GET and PUT with RANDOM files to accomplish what you want.
Posts: 3,968
Threads: 177
Joined: Apr 2022
Reputation:
219
11-03-2023, 11:44 PM
(This post was last modified: 11-03-2023, 11:47 PM by bplus.)
You want to open a file for Random (Access) and best if you set it with a fixed length record size. This allows you to read and write records to a record number.
Here is a demo for johnno for tracking Blood tests;
Code: (Select All) 'Tutorial (with help from Wiki):
' save this bas file in the folder where you want you BloodData.dat file to go first!
Type Blood
date As String * 10
level As Integer
comment As String * 50
End Type
'Make a record:
Dim Shared Record As Blood, lenRecord&, nRecs&
lenRecord& = Len(Record)
' start up the data file
Open "BloodData.dat" For Random As #1 Len = lenRecord&
Record.date = "2022/11/18"
Record.level = 101
Record.comment = "This is my comment."
'Store a record:
Put #1, 1, Record
nRecs = LOF(1) / lenRecord&
Print "number recs:"; nRecs ' good 1 lets get it
' get record
Get #1, 1, Record
Print Record.date; ":"; Record.level; ", "; Record.comment
' stick another record in there
nRecs = nRecs + 1
Record.date = "2022/11/19"
Record.level = 105
Record.comment = "This is my next comment."
Put #1, nRecs, Record
' check records
nRecs = LOF(1) / lenRecord&
Print "number recs:"; nRecs ' good 1 lets get it
For i = 1 To nRecs
Get #1, i, Record
Print Record.date; ":"; Record.level; ", "; Record.comment
Next
You create a data entry form for entering the record to file file or reading records out.
b = b + ...
Posts: 3,968
Threads: 177
Joined: Apr 2022
Reputation:
219
11-03-2023, 11:50 PM
(This post was last modified: 11-03-2023, 11:52 PM by bplus.)
Here's another demo, it's loading a Random Access file with "fake" data for practice reading and writing.
Code: (Select All) _Title "UDT to Random Access File Test" ' b+ 2021-12-24
Type Image
As String * 255 Text, FileName
As Long SzX, SzY, PosX, PosY
End Type
Const SW = 1000, SH = 700
ReDim As Image TheItem(1 To 100), TheRecord
TheItem(1).Text = FakeText$(255)
TheItem(1).FileName = FakeText$(255)
Print TheItem(1).Text
Print Len(TheItem(1).Text)
Print TheItem(1).FileName
Print Len(TheItem(1).FileName)
Print "zzz"
Sleep
'make fake data to file
For i = 1 To 100
TheItem(i).Text = FakeText$(255)
TheItem(i).SzX = 100 + Rnd * 20
TheItem(i).SzY = 70 + Rnd * 14
TheItem(i).PosX = Rnd * (SW - TheItem(i).SzX)
TheItem(i).PosY = Rnd * (SH - TheItem(i).SzY)
TheItem(i).FileName = FakeText$(255)
Next
Open "Data Dump.RA" For Random As #1 Len = Len(TheRecord)
For i = 1 To 100
'odious and tedious is this
TheRecord.Text = TheItem(i).Text
TheRecord.SzX = TheItem(i).SzX
TheRecord.SzY = TheItem(i).SzY
TheRecord.PosX = TheItem(i).PosX
TheRecord.PosY = TheItem(i).PosY
TheRecord.FileName = TheItem(i).FileName
Put #1, , TheRecord
Next
Close #1
Print "Data File Ready"
' OK we got data filed! Now can we get it back
Open "Data Dump.RA" For Random As #1 Len = Len(TheRecord)
For i = 1 To 100
Cls
Get #1, i, TheRecord
Print "Record Number:"; i
Print "Text: "; TheRecord.Text
Print "SzX:"; TheRecord.SzX
Print "SzY:"; TheRecord.SzY
Print "PosX:"; TheRecord.PosX
Print "PosY:"; TheRecord.PosY
Print "FileName:"; TheRecord.FileName
Print " zzz..."
Sleep
Next
Close #1
Function FakeText$ (lengthh)
BlankString$ = Space$(lengthh)
fini = Int(Rnd * 255) + 1
For i = 1 To fini
Mid$(BlankString$, i, 1) = Chr$(Rnd * (96 - 32) + 32)
Next
FakeText$ = BlankString$
End Function
b = b + ...
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
11-03-2023, 11:55 PM
(This post was last modified: 11-04-2023, 12:02 AM by TerryRitchie.)
I need to add this to the tutorial. I explain sequential flat files but just mention at the end of the lesson that records can be done with RANDOM. I just created a screen sticky note to remind me to do this.
Update:
Oh yuck:
Code: (Select All) TYPE Image
AS STRING * 255 Text, FileName
AS LONG SzX, SzY, PosX, PosY
END TYPE
I just saw this above. Didn't know that this was possible inside of a UDT structure but it looks rather messy in my opinion. No room for comments.
Code: (Select All) TYPE Image
Text AS STRING * 255 ' comments here
FileName AS STRING * 255 ' comments here
SzX AS LONG ' comments here
SzY AS LONG ' more comments
PosX AS LONG ' the rain in Spain
PosY AS LONG ' falls mainly on the plain
END TYPE
Ah, much better.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 3,968
Threads: 177
Joined: Apr 2022
Reputation:
219
11-03-2023, 11:55 PM
(This post was last modified: 11-03-2023, 11:56 PM by bplus.)
@PhilOfPerth have you worked with fixed length strings before?
Very important in random access files to know about fixed length strings. They help keep you record size the same size for all records with strings in them.
b = b + ...
Posts: 3,968
Threads: 177
Joined: Apr 2022
Reputation:
219
I used to do this stuff for work with GW Basic and QB4.5, parts, mold and die inventorys.
b = b + ...
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
(11-03-2023, 11:55 PM)bplus Wrote: @PhilOfPerth have you worked with fixed length strings before?
Very important in random access files to know about fixed length strings. They help keep you record size the same size for all records with strings in them.
Here's an example of a variable length, indexed filesystem at work: https://qb64phoenix.com/forum/showthread.php?tid=142
Fixed length sizes help, but they're not a necessity.
Posts: 22
Threads: 6
Joined: Oct 2023
Reputation:
0
I think there is a better way to do this using the SEEK command.
You can do this and go directly here, circumventing all of the random using BINARY symbols instead:
file$ = "c:\myfile.dat"
OPEN FILE$ for BINARY as #1
Z$= CHR$ (0) ' Null value, Gets 1 symbol at a time.
SEEK #1,10 : 'Seek out the 10th symbol of the file.
GET #1 , , Z$: 'Get the symbol.
Print Z$: 'Prints the symbol
CLOSE #1
You can do this too in GWBASIC and Qbasic both, and around the time of GWBASIC, you were limited to a FIELD length of about 128 characters or less...
But this is the way to access files efficiently at a byte level (unless you have another more recent way using file direct access).
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
(11-04-2023, 01:20 AM)JamesAlexander Wrote: I think there is a better way to do this using the SEEK command.
You can do this and go directly here, circumventing all of the random using BINARY symbols instead:
file$ = "c:\myfile.dat"
OPEN FILE$ for BINARY as #1
Z$= CHR$ (0) ' Null value, Gets 1 symbol at a time.
SEEK #1,10 : 'Seek out the 10th symbol of the file.
GET #1 , , Z$: 'Get the symbol.
Print Z$: 'Prints the symbol
CLOSE #1
You can do this too in GWBASIC and Qbasic both, and around the time of GWBASIC, you were limited to a FIELD length of about 128 characters or less...
But this is the way to access files efficiently at a byte level (unless you have another more recent way using file direct access).
Thanks James. I'll experiment with this. The records are of different lengths, so I may need to use fixed-length strings as also suggested.
|