Solved

Read/Write a 3 dim. array to/from File

Posted on 1998-07-01
8
242 Views
Last Modified: 2010-05-03
I am attempting to simulate some yet to built hardware - so I need a rather large array to hold the data... And I want to
be able to save/read to/from disk...


I have a three dim array that I want to read/write to a file quickly (i.e. not a byte at a time) via API calls:

Form1 code (form has a dialog control on it)
Private Sub Form_Load()
   FileIO = WriteSimFile
   File_Manager
   FileIO = ReadSimFile
   File_Manager
End Sub


Module1 code:
Option Explicit

Declare Function OpenFile& Lib "kernel32" (ByVal lpFileName As String, lpReOpenBuff As OFSTRUCT, ByVal wStyle As Long)
Declare Function ReadFile& Lib "kernel32" (ByVal hFile As Long, lpBuffer As Integer, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long)
Declare Function WriteFile& Lib "kernel32" (ByVal hFile As Long, lpBuffer As Integer, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long)
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long

'Common Dialog Control
'Action Property
Global Const DLG_FILE_OPEN = 1
Global Const DLG_FILE_SAVE = 2
Global Const DLG_COLOR = 3
Global Const DLG_FONT = 4
Global Const DLG_PRINT = 5
Global Const DLG_HELP = 6

'File Open/Save Dialog Flags
Global Const OFN_READONLY = &H1&
Global Const OFN_OVERWRITEPROMPT = &H2&
Global Const OFN_HIDEREADONLY = &H4&
Global Const OFN_NOCHANGEDIR = &H8&
Global Const OFN_SHOWHELP = &H10&
Global Const OFN_NOVALIDATE = &H100&
Global Const OFN_ALLOWMULTISELECT = &H200&
Global Const OFN_EXTENSIONDIFFERENT = &H400&
Global Const OFN_PATHMUSTEXIST = &H800&
Global Const OFN_FILEMUSTEXIST = &H1000&
Global Const OFN_CREATEPROMPT = &H2000&
Global Const OFN_SHAREAWARE = &H4000&
Global Const OFN_NOREADONLYRETURN = &H8000&
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const CREATE_ALWAYS = 2
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_FLAG_WRITE_THROUGH = &H80000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const FILE_FLAG_NO_BUFFERING = &H20000000
Private Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Private Const FILE_BEGIN = 0
Private Const FILE_CURRENT = 1
Private Const FILE_END = 2
Private Const INFINITE = &HFFFF      '  Infinite timeout
Private Const INVALID_HANDLE_VALUE = -1


' OpenFile() Structure
Type OFSTRUCT
        cBytes As Byte
        fFixedDisk As Byte
        nErrCode As Integer
        Reserved1 As Integer
        Reserved2 As Integer
        szPathName As String * 128
End Type

Dim DaLength As Long
Dim DaStruct As OFSTRUCT
Dim BytesActuallyWritten As Long
Dim BytesActuallyRead As Long
Dim result As Long
Dim fhnd As Long

Public Const WriteSimFile = 1
Public Const ReadSimFile = 2

Public Const HARDWARE_REG_00 = 0
Public Const HARDWARE_REG_01 = HARDWARE_REG_00 + 1
Public Const HARDWARE_REG_02 = HARDWARE_REG_01 + 1
Public Const HARDWARE_REG_03 = HARDWARE_REG_02 + 1
Public Const HARDWARE_REG_04 = HARDWARE_REG_03 + 1
Public Const HARDWARE_REG_05 = HARDWARE_REG_04 + 1
Public Const HARDWARE_REG_06 = HARDWARE_REG_05 + 1
Public Const HARDWARE_REG_07 = HARDWARE_REG_06 + 1
Public Const HARDWARE_REG_08 = HARDWARE_REG_07 + 1
Public Const HARDWARE_REG_09 = HARDWARE_REG_08 + 1
Public Const HARDWARE_REG_10 = HARDWARE_REG_09 + 1
Public Const HARDWARE_REG_11 = HARDWARE_REG_10 + 1
Public Const HARDWARE_REG_12 = HARDWARE_REG_11 + 1

Public Const EndOfHardwareArray = HARDWARE_REG_12

Public Const Max_Seconds = 59            'Number of seconds in a minute (counting #s)
Public Const HZ_500 = 499                'Number of tics in a sec @ 500 hz (counting #s)
Public HW(Max_Seconds, HZ_500, EndOfHardwareArray) As Integer  'System array, 60 sec * 500 hz * array
Public FileIO As Integer


Sub File_Manager()

    Select Case (FileIO)
           
       Case WriteSimFile
          Form1.Caption = "Write a Simulation File"
          Form1.CommonDialog1.InitDir = CurDir
          Form1.CommonDialog1.DefaultExt = "*.ref"
          Form1.CommonDialog1.DialogTitle = "Select a simulation profile to write to"
          Form1.CommonDialog1.Filter = "REF FILE|*.sim"
          Form1.CommonDialog1.FilterIndex = 1
          Form1.CommonDialog1.Flags = OFN_SHOWHELP
          Form1.CommonDialog1.CancelError = True
          On Error GoTo errCancel
          Form1.CommonDialog1.Action = DLG_FILE_SAVE

          fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
          DaLength = CLng(2) * CLng(Max_Seconds) * CLng(HZ_500) * CLng(EndOfHardwareArray)
          result = WriteFile(fhnd, ByVal HW(0, 0, 0), DaLength, BytesActuallyWritten, 0)
         

       Case ReadSimFile

          Form1.Caption = "Read a Simulation File"
          Form1.CommonDialog1.InitDir = CurDir
          Form1.CommonDialog1.DefaultExt = "*.ref"
          Form1.CommonDialog1.DialogTitle = "Select a simulation profile to write to"
          Form1.CommonDialog1.Filter = "REF FILE|*.sim"
          Form1.CommonDialog1.FilterIndex = 1
          Form1.CommonDialog1.Flags = OFN_SHOWHELP
          Form1.CommonDialog1.CancelError = True
          On Error GoTo errCancel
          Form1.CommonDialog1.Action = DLG_FILE_OPEN
          fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
          result = ReadFile(fhnd, HW(0, 0, 0), Len(HW(Max_Seconds, HZ_500, EndOfHardwareArray)), BytesActuallyRead, 0)
         
   End Select
errCancel:

result = CloseHandle(fhnd)

End Sub
0
Comment
Question by:esler
  • 4
  • 4
8 Comments
 
LVL 6

Expert Comment

by:alamo
ID: 1464730
You are very close!

Here's what I noticed:

- you weren't calculating the array size quite right (not taking element 0 into account in the write, completely wrong in the read)
- you were opening the file to read it using CREATE_ALWAYS, so you overwrote it when you opened it
- the Byval in the WriteFile meant you were passing the value of HW(0,0,0) not its address.

In general it's more reliable to use LBound and UBound when doing things like this, since you'll adjust automatically if the array demensions change (or you decide to get rid of element 0 of an array).

Fix those things and it'll work just fine. Here are the working lines:

To write:

fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
DaLength = LenB(HW(1, 1, 1)) * (UBound(HW, 1) - LBound(HW, 1) + 1) * (UBound(HW, 2) - LBound(HW, 2) + 1) * (UBound(HW, 3) - LBound(HW, 3) + 1)
result = WriteFile(fhnd, HW(LBound(HW, 1), LBound(HW, 2), LBound(HW, 3)), DaLength, BytesActuallyWritten, 0)

To read:
fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
DaLength = LenB(HW(1, 1, 1)) * (UBound(HW, 1) - LBound(HW, 1) + 1) * (UBound(HW, 2) - LBound(HW, 2) + 1) * (UBound(HW, 3) - LBound(HW, 3) + 1)
result = ReadFile(fhnd, HW(LBound(HW, 1), LBound(HW, 2), LBound(HW, 3)), DaLength, BytesActuallyRead, 0)

and you need Const OPEN_ALWAYS = 4

Good luck!
0
 

Author Comment

by:esler
ID: 1464731
I liked your comment about using UBound and LBound :)


I tried the rest of the code, but it did not fly...  The var BytesActuallyWritten is still zero, and the length of the file save is zero bytes long....

Here is how I implemented what you suggested:

The form code is unchanged as:

Form1 code (form has a dialog control on it)
 Private Sub Form_Load()
    FileIO = WriteSimFile
    File_Manager
    FileIO = ReadSimFile
    File_Manager
 End Sub

The  module code was modified as:
Option Explicit

Declare Function ReadFile& Lib "kernel32" (ByVal hFile As Long, lpBuffer As Integer, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long)
Declare Function WriteFile& Lib "kernel32" (ByVal hFile As Long, lpBuffer As Integer, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long)
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long

'Common Dialog Control
'Action Property
Global Const DLG_FILE_OPEN = 1
Global Const DLG_FILE_SAVE = 2
Global Const DLG_COLOR = 3
Global Const DLG_FONT = 4
Global Const DLG_PRINT = 5
Global Const DLG_HELP = 6

'File Open/Save Dialog Flags
Global Const OFN_READONLY = &H1&
Global Const OFN_OVERWRITEPROMPT = &H2&
Global Const OFN_HIDEREADONLY = &H4&
Global Const OFN_NOCHANGEDIR = &H8&
Global Const OFN_SHOWHELP = &H10&
Global Const OFN_NOVALIDATE = &H100&
Global Const OFN_ALLOWMULTISELECT = &H200&
Global Const OFN_EXTENSIONDIFFERENT = &H400&
Global Const OFN_PATHMUSTEXIST = &H800&
Global Const OFN_FILEMUSTEXIST = &H1000&
Global Const OFN_CREATEPROMPT = &H2000&
Global Const OFN_SHAREAWARE = &H4000&
Global Const OFN_NOREADONLYRETURN = &H8000&
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const CREATE_ALWAYS = 2
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_FLAG_WRITE_THROUGH = &H80000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const FILE_FLAG_NO_BUFFERING = &H20000000
Private Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Private Const FILE_BEGIN = 0
Private Const FILE_CURRENT = 1
Private Const FILE_END = 2
Private Const INFINITE = &HFFFF      '  Infinite timeout
Private Const INVALID_HANDLE_VALUE = -1



Dim DaLength As Long
Dim BytesActuallyWritten As Long
Dim BytesActuallyRead As Long
Dim result As Long
Dim fhnd As Long

Public Const WriteSimFile = 1
Public Const ReadSimFile = 2
Public Const OPEN_ALWAYS = 4
Public Const HARDWARE_REG_00 = 0
Public Const HARDWARE_REG_01 = HARDWARE_REG_00 + 1
Public Const HARDWARE_REG_02 = HARDWARE_REG_01 + 1
Public Const HARDWARE_REG_03 = HARDWARE_REG_02 + 1
Public Const HARDWARE_REG_04 = HARDWARE_REG_03 + 1
Public Const HARDWARE_REG_05 = HARDWARE_REG_04 + 1
Public Const HARDWARE_REG_06 = HARDWARE_REG_05 + 1
Public Const HARDWARE_REG_07 = HARDWARE_REG_06 + 1
Public Const HARDWARE_REG_08 = HARDWARE_REG_07 + 1
Public Const HARDWARE_REG_09 = HARDWARE_REG_08 + 1
Public Const HARDWARE_REG_10 = HARDWARE_REG_09 + 1
Public Const HARDWARE_REG_11 = HARDWARE_REG_10 + 1
Public Const HARDWARE_REG_12 = HARDWARE_REG_11 + 1

Public Const EndOfHardwareArray = HARDWARE_REG_12

Public Const Max_Seconds = 59            'Number of seconds in a minute (counting #s)
Public Const HZ_500 = 499                'Number of tics in a sec @ 500 hz (counting #s)
Public HW(Max_Seconds, HZ_500, EndOfHardwareArray) As Integer  'System array, 60 sec * 500 hz * array
Public FileIO As Integer


Sub File_Manager()

    Select Case (FileIO)
           
       Case WriteSimFile
          Form1.Caption = "Write a Simulation File"
          Form1.CommonDialog1.InitDir = CurDir
          Form1.CommonDialog1.DefaultExt = "*.ref"
          Form1.CommonDialog1.DialogTitle = "Select a simulation profile to write to"
          Form1.CommonDialog1.Filter = "SIM FILE|*.sim"
          Form1.CommonDialog1.FilterIndex = 1
          Form1.CommonDialog1.Flags = OFN_SHOWHELP
          Form1.CommonDialog1.CancelError = True
          On Error GoTo errCancel
          Form1.CommonDialog1.Action = DLG_FILE_SAVE


          fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
          DaLength = LenB(HW(1, 1, 1)) * (UBound(HW, 1) - LBound(HW, 1) + 1) * (UBound(HW, 2) - LBound(HW, 2) + 1) * (UBound(HW, 3) - LBound(HW, 3) + 1)
          result = WriteFile(fhnd, HW(LBound(HW, 1), LBound(HW, 2), LBound(HW, 3)), DaLength, BytesActuallyWritten, 0)


       Case ReadSimFile

          Form1.Caption = "Read a Simulation File"
          Form1.CommonDialog1.InitDir = CurDir
          Form1.CommonDialog1.DefaultExt = "*.ref"
          Form1.CommonDialog1.DialogTitle = "Select a simulation profile to write to"
          Form1.CommonDialog1.Filter = "REF FILE|*.sim"
          Form1.CommonDialog1.FilterIndex = 1
          Form1.CommonDialog1.Flags = OFN_SHOWHELP
          Form1.CommonDialog1.CancelError = True
          On Error GoTo errCancel
          Form1.CommonDialog1.Action = DLG_FILE_OPEN

          fhnd = CreateFile(Form1.CommonDialog1.filename, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_RANDOM_ACCESS, 0)
          DaLength = LenB(HW(1, 1, 1)) * (UBound(HW, 1) - LBound(HW, 1) + 1) * (UBound(HW, 2) - LBound(HW, 2) + 1) * (UBound(HW, 3) - LBound(HW, 3) + 1)
          result = ReadFile(fhnd, HW(LBound(HW, 1), LBound(HW, 2), LBound(HW, 3)), DaLength, BytesActuallyRead, 0)
         
   End Select
errCancel:

result = CloseHandle(fhnd)

End Sub
0
 

Author Comment

by:esler
ID: 1464732
Adjusted points to 250
0
 
LVL 6

Expert Comment

by:alamo
ID: 1464733
It almost has to be the parameters to the Create or Read or Write... I didn't look very closely at each one, it worked for me first time after I made the changes above. (It created a 780,000 byte file). I did just notice the last parameter in ReadFile and WriteFile, lpOverlapped,  needs to be ByVal if you are passing 0 - but since the file wasn't opened for overlapped IO I wouldn't think this would make a difference.

I will take a closer look. In the meantime: could you check that you are getting a valid handle from CreateFile? It could be that for some reason on your system the file creation is failing. Also, print out DaLength and make sure it's 780000.
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 6

Accepted Solution

by:
alamo earned 250 total points
ID: 1464734
I just looked more closely at the WriteFile and ReadFile arguments, and it does in fact pay attention to lpOverlapped even if the file wasn't opened for overlapped IO. So change those to ByVal and that should solve that problem.

If that doesn't solve the entire problem, make sure the handle is correct and DaLength is correct like I mentioned in my last comment.

By the way, in the CreateFile FILE_FLAG_SEQUENTIAL_SCAN would be a little faster potentially than FILE_FLAG_RANDOM_ACCESS since you are in fact reading and writing in one chunk.
0
 

Author Comment

by:esler
ID: 1464735
YES - SUCCESS!
Thanks alot,


0
 

Author Comment

by:esler
ID: 1464736
- The ByVal was the missing part...
0
 
LVL 6

Expert Comment

by:alamo
ID: 1464737
Excellent! I guess when I ran it the first time without the Byval I just got lucky.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
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…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

708 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

20 Experts available now in Live!

Get 1:1 Help Now