Home > Archive > Visual Basic > March 2004 > GET on disk, but what in memory ?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
GET on disk, but what in memory ?
|
|
| gps 4 pilots 2004-03-28, 9:59 pm |
| I use this small code to load a 2 Megs binary file into memory. The file
contains 6400 records of various lenght, and various type. With the words
"Get" and "S ", I can retrieve the data on disk but how do I do that when
in memory, in a byte array ?
For example, if I know that at address 454,234, there is a Long followed by
2 integers. I want to learn how to do, in memory, the work that Get and S
do, on disk ?
Many thanks
Jacquelin Hardy
Private Sub Form_Load()
Dim frfi As Integer
Dim Filename As String
Dim b() As Byte
Filename = "C:\\DataFile\t.bin"
frfi = FreeFile
Open Filename For Binary access Read Lock Read Write As #frfi
ReDim Preserve s(LOF(frfi))
Get #frfi , , b
Close frfi
End Sub
| |
| Bob O`Bob 2004-03-28, 9:59 pm |
| gps 4 pilots wrote:
>
> I use this small code to load a 2 Megs binary file into memory. The file
> contains 6400 records of various lenght, and various type. With the words
> "Get" and "S ", I can retrieve the data on disk but how do I do that when
> in memory, in a byte array ?
>
> For example, if I know that at address 454,234, there is a Long followed by
> 2 integers. I want to learn how to do, in memory, the work that Get and S
> do, on disk ?
>
> Many thanks
>
> Jacquelin Hardy
>
> Private Sub Form_Load()
>
> Dim frfi As Integer
> Dim Filename As String
> Dim b() As Byte
>
> Filename = "C:\\DataFile\t.bin"
> frfi = FreeFile
> Open Filename For Binary access Read Lock Read Write As #frfi
> ReDim Preserve s(LOF(frfi))
> Get #frfi , , b
> Close frfi
> End Sub
I have serious doubts that code actually works.
Why are you ReDim'ing some undeclared array "s"?
If you actually get the file into a byte array, it should be a straightforward
process of computing the appropriate index into that array and then moving the
bytes of interest into buffer variables of the types those bytes represent.
Bob
--
| |
| Jacquelin Hardy 2004-03-28, 9:59 pm |
| "process of computing the appropriate index into that array "
How would you do that Bob ? There isn't left$ or mid$ or right$ for bytes ?
Many thanks
JH
"Bob O`Bob" <filterbob@yahoogroups.com> wrote in message
news:40660645.38E6@yahoogroups.com...
> gps 4 pilots wrote:
words[color=darkred]
when[color=darkred]
by[color=darkred]
S [color=darkred]
>
>
> I have serious doubts that code actually works.
> Why are you ReDim'ing some undeclared array "s"?
>
> If you actually get the file into a byte array, it should be a
straightforward
> process of computing the appropriate index into that array and then moving
the
> bytes of interest into buffer variables of the types those bytes
represent.
>
>
>
> Bob
> --
| |
| Bob O`Bob 2004-03-28, 9:59 pm |
| Jacquelin Hardy wrote:
>
> "process of computing the appropriate index into that array "
>
> How would you do that Bob ? There isn't left$ or mid$ or right$ for bytes ?
>
b(n)
Bob
--
| |
| Bob O`Bob 2004-03-28, 9:59 pm |
| gps 4 pilots wrote:
> For example, if I know that at address 454,234, there is a Long followed by
> 2 integers. I want to learn how to do, in memory, the work that Get and S
> do, on disk ?
An example of _a_ way to do that might look something like this.
(none of this is tested, and I haven't done any LSet code
for a while, so "air code" warnings apply)
Type myLong
a as long
end type
Type myInteger
a as integer
end type
Type my4Bytes
a(0 to 3) as byte
end type
type my2Bytes
a(0 to 1) as byte
end type
dim mlBuf as myLong
dim miBuf as myInteger
dim m4 as my4Bytes
dim m2 as my2Bytes
[...]
cur_address = 454234
for i = 0 to 3
m4.a(i) = b(cur_address + i)
next
lset FirstLong = m4
cur_address = cur_address + 4
for i = 0 to 1
m2.a(i) = b(cur_address + i)
next
lset FirstInt = m2
cur_address = cur_address + 2
for i = 0 to 1
m2.a(i) = b(cur_address + i)
next
lset SecondInt = m2
Of course all those loops and the LSet stuff could probably be abstracted
into functions ...
function Extract_Long (b() as byte, offset as long) as Long
function Extract_Integer (b() as byte, offset as long) as Integer
And for all I know someone could be along in a moment to post something
more efficient, or more readable, or both.
Bob
--
| |
| gps 4 pilots 2004-03-28, 9:59 pm |
| Many thanks Bob,
JH
"Bob O`Bob" <filterbob@yahoogroups.com> wrote in message
news:40661278.5A00@yahoogroups.com...
> gps 4 pilots wrote:
>
by[color=darkred]
S [color=darkred]
>
> An example of _a_ way to do that might look something like this.
> (none of this is tested, and I haven't done any LSet code
> for a while, so "air code" warnings apply)
>
>
> Type myLong
> a as long
> end type
> Type myInteger
> a as integer
> end type
> Type my4Bytes
> a(0 to 3) as byte
> end type
> type my2Bytes
> a(0 to 1) as byte
> end type
> dim mlBuf as myLong
> dim miBuf as myInteger
> dim m4 as my4Bytes
> dim m2 as my2Bytes
>
> [...]
>
> cur_address = 454234
> for i = 0 to 3
> m4.a(i) = b(cur_address + i)
> next
> lset FirstLong = m4
>
> cur_address = cur_address + 4
> for i = 0 to 1
> m2.a(i) = b(cur_address + i)
> next
> lset FirstInt = m2
>
> cur_address = cur_address + 2
> for i = 0 to 1
> m2.a(i) = b(cur_address + i)
> next
> lset SecondInt = m2
>
>
> Of course all those loops and the LSet stuff could probably be abstracted
> into functions ...
>
> function Extract_Long (b() as byte, offset as long) as Long
> function Extract_Integer (b() as byte, offset as long) as Integer
>
> And for all I know someone could be along in a moment to post something
> more efficient, or more readable, or both.
>
> Bob
> --
| |
| J French 2004-03-28, 9:59 pm |
| On Sat, 27 Mar 2004 17:19:36 -0500, "gps 4 pilots"
<gps4pilots@hotmail.com> wrote:
>I use this small code to load a 2 Megs binary file into memory. The file
>contains 6400 records of various lenght, and various type. With the words
>"Get" and "S ", I can retrieve the data on disk but how do I do that when
>in memory, in a byte array ?
For compatibility with your existing routines I would make the Byte
Array 1 based
eg: ReDim B( 1 To FileLen( TheFile$ )
I would look at the API CopyMemory for reading bytes into Simple
Variables and Strings
- front those with similar calls such as :-
MemGetInt S Pos, TgtInt
MemGetLng S Pos, TgtLong
MemGetStr S Pos, TgtString
If S Pos is 0 (zero) then use the remembered S Pos
- otherwise move your pseudo file pointer
You need to watch out for UDTs
- it could be nasty if you try to grab the entire UDT
I would also box the lot in a Class
Here are some examples using CopyMemory :-
Option Explicit
Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" _
(pDst As Any, _
pSrc As Byte, _
ByVal ByteLen As Long)
Private Sub Command1_Click()
Dim B(1 To 6) As Byte
Dim S As String, L9 As Long
Dim I As Integer
For L9 = 1 To 4
B(L9) = Asc(Mid$("TEST", L9, 1))
Next
S$ = Space$(4)
Call CopyMemory(ByVal S$, B(1), Len(S$))
Me.Print S$
B(5) = 123
Call CopyMemory(I, B(5), Len(I))
Me.Print I
End Sub
| |
|
|
| J French 2004-03-28, 9:59 pm |
| On Sun, 28 Mar 2004 09:04:31 -0500, "gps 4 pilots"
<gps4pilots@hotmail.com> wrote:
>Thank you JFrench,
>
> for your code and comments. I kept looking for more things and I found this
>interesting article from Steven Roman, Ph.D, about the CopyMemory API.
>
>Good reading
>
>http://msdn.microsoft.com/library/d...-us/dnovba00/ht
>ml/LightningStrings.asp
>
Yes, it describes the BSTR structure
- not relevant to your problem
- but useful if you ever want to write a SwapStr routine
..... remember to watch out for UDTs
- even 'Friend' is not your friend when things are pragma packed
| |
| Karl E. Peterson 2004-03-29, 5:30 pm |
| Jacquelin Hardy <jachardy@removethisvideotron.ca> wrote:
> "process of computing the appropriate index into that array "
>
> How would you do that Bob ? There isn't left$ or mid$ or right$ for bytes ?
You're now "stuck" with CopyMemory, from b(x) to whichever variable you'd prefer.
(Assuming working with the bytes, in situ, isn't desirable.
--
[Microsoft Basic: 1976-2001, RIP]
| |
| Bob O`Bob 2004-03-29, 6:34 pm |
| Karl E. Peterson wrote:
> Jacquelin Hardy <jachardy@removethisvideotron.ca> wrote:
>
> You're now "stuck" with CopyMemory, from b(x) to whichever variable you'd prefer.
> (Assuming working with the bytes, in situ, isn't desirable.
One *might* be able to use CopyMemory in [dangerous] ways
similar to those employed by the "soft reference" tricks,
to end up with multiple object variables of different descriptions
occupying the same memory.
Though I don't think I'd even consider trying it, except maybe as
an intellectual exercise. ("just to see if it can be made to work")
Bob
--
| |
| Karl E. Peterson 2004-03-29, 6:34 pm |
| Bob O`Bob <filterbob@yahoogroups.com> wrote:
> Karl E. Peterson wrote:
>
>
> One *might* be able to use CopyMemory in [dangerous] ways
> similar to those employed by the "soft reference" tricks,
> to end up with multiple object variables of different descriptions
> occupying the same memory.
>
> Though I don't think I'd even consider trying it, except maybe as
> an intellectual exercise. ("just to see if it can be made to work")
I'd be hard-pressed to believe it wouldn't be a false economy!
--
[Microsoft Basic: 1976-2001, RIP]
| |
| Rick Rothstein 2004-03-29, 6:34 pm |
| > "process of computing the appropriate index into that array "
>
> There isn't left$ or mid$ or right$ for bytes ?
Sure there is...
Dim CharPos As Long
Dim CharLen As Long
Dim S As String
Dim ABC As String
Dim DEFGH As String
Dim IJK As String
Dim B() As Byte
S = "ABCDEFGHIJK"
B = S
CharPos = 4
CharLen = 5
ABC = LeftB$(B, 2 * CharLen - 4)
DEFGH = MidB$(B, 2 * CharPos - 1, 2 * CharLen)
IJK = RightB$(B, UBound(B) - 2 * CharLen - 5)
MsgBox ABC & vbCrLf & DEFGH & vbCrLf & IJK
Just remember, there are two bytes stored for every character (makes
computing the arguments a little tricky<g> )
Rick - MVP
| |
| Rick Rothstein 2004-03-29, 6:34 pm |
| > > "process of computing the appropriate index into that array "
>
> Sure there is...
>
> Dim CharPos As Long
> Dim CharLen As Long
> Dim S As String
> Dim ABC As String
> Dim DEFGH As String
> Dim IJK As String
> Dim B() As Byte
> S = "ABCDEFGHIJK"
> B = S
> CharPos = 4
> CharLen = 5
> ABC = LeftB$(B, 2 * CharLen - 4)
> DEFGH = MidB$(B, 2 * CharPos - 1, 2 * CharLen)
> IJK = RightB$(B, UBound(B) - 2 * CharLen - 5)
> MsgBox ABC & vbCrLf & DEFGH & vbCrLf & IJK
>
> Just remember, there are two bytes stored for every character (makes
> computing the arguments a little tricky<g> )
Sorry about the assignment line to IJK... I meant to use the CharPos and
CharLen to calculate it. Substitute this line for the one I posted...
IJK = RightB$(B, UBound(B) - 2 * (CharPos + CharLen) + 3)
Rick - MVP
| |
| Larry Serflaten 2004-03-29, 7:32 pm |
|
"Bob O`Bob" <filterbob@yahoogroups.com> wrote
>
>
> An example of _a_ way to do that might look something like this.
> (none of this is tested, and I haven't done any LSet code
> for a while, so "air code" warnings apply)
Just to continue the discussion, I would suggest that the decision be
made to either hold the data in a string, and use LSet, or hold the data
in a Byte array and use CopyMemory. The latter will be at least twice
as fast because of the redundant copying of data into and out of
the UDT's that LSet requires. While CopyMemory could be used
in both cases, there would be no reason to mess with binary data
held in strings, when a byte array would do better. Conversly, LSet
works best when strings are used. (This may be a VB5 limitation).
Using Byte arrays and CopyMemory, is pretty straight forward, but
here is an example using LSet and strings....
HTH
LFS
Option Explicit
Private Type CnvValue
Value As Long
End Type
Private Type CnvData
Bytes As String * 4
End Type
Private Enum CnvSize
csInteger = 2
csLong = 4
End Enum
Private Data As String
Private Sub Form_Load()
Dim Offset As Long
Dim Value As Long
Data = StrConv("ABCDEFGHIJKLMNOP", vbFromUnicode)
Offset = 3 ' simulated 454,234
' Pull Long from data
Value = Data2Value(Offset, CnvSize.csLong)
Debug.Print "Before switching"
Debug.Print Value, StrConv(Data, vbUnicode)
Value = Value + &H20202020 ' to lower case
' Insert Long into data
Value2Data Value, Offset, CnvSize.csLong
Debug.Print "After Long switch"
Debug.Print Value, StrConv(Data, vbUnicode)
Offset = 10
' Ditto for Integer
Value = Data2Value(Offset, CnvSize.csInteger)
Value = Value + &H2020
Value2Data Value, Offset, CnvSize.csInteger
Debug.Print "After Integer switch"
Debug.Print Value, StrConv(Data, vbUnicode)
End Sub
Private Function Data2Value(ByVal Offset As Long, ByVal Size As CnvSize) As Long
Dim tmpValue As CnvValue
Dim tmpData As CnvData
tmpData.Bytes = MidB(Data, Offset, Size) ' Copy #1
LSet tmpValue = tmpData ' Copy #2
Data2Value = tmpValue.Value ' Copy #3
End Function
Private Sub Value2Data(ByVal Value As Long, ByVal Offset As Long, ByVal Size As CnvSize)
Dim tmpValue As CnvValue
Dim tmpData As CnvData
tmpValue.Value = Value
LSet tmpData = tmpValue
MidB(Data, Offset, Size) = MidB(tmpData.Bytes, 1, Size)
End Sub
| |
| Rick Rothstein 2004-03-29, 7:32 pm |
| It just occurred to me... those variable names I chose might be a source of
confusion as they are identical to the string value they will print out.
Here's the same code, but with better named variables...
Dim CharPos As Long
Dim CharLen As Long
Dim S As String
Dim FirstPart As String
Dim MiddlePart As String
Dim EndPart As String
Dim B() As Byte
S = "ABCDEFGHIJK"
B = S
CharPos = 4
CharLen = 5
FirstPart = LeftB$(B, 2 * CharLen - 4)
MiddlePart = MidB$(B, 2 * CharPos - 1, 2 * CharLen)
EndPart = RightB$(B, UBound(B) - 2 * (CharPos + CharLen) + 3)
MsgBox FirstPart & vbCrLf & MiddlePart & vbCrLf & EndPart
Rick - MVP
"Rick Rothstein" <rickNOSPAMnews@NOSPAMcomcast.net> wrote in message
news:%23rOK16dFEHA.3324@TK2MSFTNGP09.phx.gbl...
>
> Sorry about the assignment line to IJK... I meant to use the CharPos and
> CharLen to calculate it. Substitute this line for the one I posted...
>
> IJK = RightB$(B, UBound(B) - 2 * (CharPos + CharLen) + 3)
>
> Rick - MVP
>
>
| |
| Larry Serflaten 2004-03-29, 7:32 pm |
|
"Larry Serflaten" <serflaten@usinternet.com> wrote
> Private Function Data2Value(ByVal Offset As Long, ByVal Size As CnvSize) As Long
> Dim tmpValue As CnvValue
> Dim tmpData As CnvData
>
> tmpData.Bytes = MidB(Data, Offset, Size) ' Copy #1
> LSet tmpValue = tmpData ' Copy #2
> Data2Value = tmpValue.Value ' Copy #3
>
> End Function
I was working with Longs and all appeared well, but a closer
look revealed that more testing was needed. The above function
returns a Long, but if it was supposed to return an Integer then
the unused parts of the UDT string need to be 0'd out:
tmpData.Bytes = MidB(Data, Offset, Size) & String$(2, 0) ' Copy #1
VB initializes the string to all spaces which throws off the value
if they are not filled by that 1st copy instruction.
As can be seen from the print out of the Data string, the other
function copies in only those bytes as are requested.
I hate it when that happens!
<g>
LFS
|
|
|
|
|