Download from ME
Option Explicit ' 'HugeBinaryFile '============== ' 'A class for doing simple binary I/O on very large disk files '(well over the usual 2GB limit). It only does I/O using Byte 'arrays, and makes use of Currency values that are scaled to 'whole numbers in places: ' ' For a file of one byte the FileLen property returns 1.0000 as ' its value. ' 'Operation is similar in many ways to native VB Get#/Put# I/O, for 'example the EOF property must be checked after a ReadBytes() call. 'You must also Dim/Redim buffers to desired sizes before calling 'ReadBytes() or WriteBytes(). ' 'Short (signed Long) relative seeks and long (unsigned Currency) 'absolute seeks from 0 may be done. ' 'AutoFlush may be set True to force buffer flushes on every write. 'The Flush() method may be called explicitly if necessary. ' Public Enum HBF_Errors HBF_UNKNOWN_ERROR = 45600 HBF_FILE_ALREADY_OPEN HBF_OPEN_FAILURE HBF_SEEK_FAILURE HBF_FILELEN_FAILURE HBF_READ_FAILURE HBF_WRITE_FAILURE HBF_FILE_ALREADY_CLOSED End Enum Private Const HBF_SOURCE = "HugeBinaryFile" Private Const GENERIC_WRITE As Long = &H40000000 Private Const GENERIC_READ As Long = &H80000000 Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80& Private Const CREATE_ALWAYS = 2 Private Const OPEN_ALWAYS = 4 Private Const INVALID_HANDLE_VALUE = -1 Private Const INVALID_SET_FILE_POINTER = -1 Private Const INVALID_FILE_SIZE = -1 Private Const FILE_BEGIN = 0, FILE_CURRENT = 1, FILE_END = 2 Private Type MungeCurr Value As Currency End Type Private Type Munge2Long LowVal As Long HighVal As Long End Type Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" ( _ ByVal dwFlags As Long, _ lpSource As Long, _ ByVal dwMessageId As Long, _ ByVal dwLanguageId As Long, _ ByVal lpBuffer As String, _ ByVal nSize As Long, _ Arguments As Any) As Long Private Declare Function ReadFile Lib "kernel32" ( _ ByVal hFile As Long, _ lpBuffer As Any, _ ByVal nNumberOfBytesToRead As Long, _ lpNumberOfBytesRead As Long, _ ByVal lpOverlapped As Long) As Long Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function GetFileSize Lib "kernel32" ( _ ByVal hFile As Long, _ lpFileSizeHigh As Long) As Long Private Declare Function WriteFile Lib "kernel32" ( _ ByVal hFile As Long, _ lpBuffer As Any, _ ByVal nNumberOfBytesToWrite As Long, _ lpNumberOfBytesWritten As Long, _ ByVal lpOverlapped As Long) As Long Private 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 Private Declare Function SetFilePointer Lib "kernel32" ( _ ByVal hFile As Long, _ ByVal lDistanceToMove As Long, _ lpDistanceToMoveHigh As Long, _ ByVal dwMoveMethod As Long) As Long Private Declare Function FlushFileBuffers Lib "kernel32" ( _ ByVal hFile As Long) As Long Private hFile As Long Private sFName As String Private fAutoFlush As Boolean Private fEOF As Boolean Private C As MungeCurr Private L As Munge2Long Public Property Get AutoFlush() As Boolean RaiseErrorIfClosed AutoFlush = fAutoFlush End Property Public Property Let AutoFlush(ByVal NewVal As Boolean) RaiseErrorIfClosed fAutoFlush = NewVal End Property Public Property Get FileHandle() As Long RaiseErrorIfClosed FileHandle = hFile End Property Public Property Get FileLen() As Currency RaiseErrorIfClosed L.LowVal = GetFileSize(hFile, L.HighVal) If L.LowVal = INVALID_FILE_SIZE Then If Err.LastDllError Then RaiseError HBF_FILELEN_FAILURE End If LSet C = L FileLen = C.Value * 10000@ End Property Public Property Get FileName() As String RaiseErrorIfClosed FileName = sFName End Property Public Property Get EOF() As Boolean RaiseErrorIfClosed EOF = fEOF End Property Public Property Get IsOpen() As Boolean IsOpen = hFile <> INVALID_HANDLE_VALUE End Property Public Sub CloseFile() RaiseErrorIfClosed CloseHandle hFile sFName = "" fAutoFlush = False fEOF = False hFile = INVALID_HANDLE_VALUE End Sub Public Sub Flush() RaiseErrorIfClosed FlushFileBuffers hFile End Sub Public Sub OpenFile(ByVal OpenFileName As String) If hFile <> INVALID_HANDLE_VALUE Then RaiseError HBF_FILE_ALREADY_OPEN End If hFile = CreateFile(OpenFileName, GENERIC_WRITE Or GENERIC_READ, 0, _ 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) If hFile = INVALID_HANDLE_VALUE Then RaiseError HBF_OPEN_FAILURE End If sFName = OpenFileName End Sub Public Function ReadBytes(ByRef Buffer() As Byte) As Long RaiseErrorIfClosed If ReadFile(hFile, _ Buffer(LBound(Buffer)), _ UBound(Buffer) - LBound(Buffer) + 1, _ ReadBytes, _ 0) Then If ReadBytes = 0 Then fEOF = True End If Else RaiseError HBF_READ_FAILURE End If End Function Public Sub SeekAbsolute(ByVal Position As Currency) RaiseErrorIfClosed C.Value = Position / 10000@ LSet L = C If SetFilePointer(hFile, L.LowVal, L.HighVal, FILE_BEGIN) _ = INVALID_SET_FILE_POINTER Then If Err.LastDllError Then RaiseError HBF_SEEK_FAILURE End If End Sub Public Sub SeekEnd() RaiseErrorIfClosed If SetFilePointer(hFile, 0&, ByVal 0&, FILE_END) _ = INVALID_SET_FILE_POINTER Then RaiseError HBF_SEEK_FAILURE End If End Sub Public Sub SeekRelative(ByVal Offset As Long) 'Offset is signed. RaiseErrorIfClosed If SetFilePointer(hFile, Offset, ByVal 0&, FILE_CURRENT) _ = INVALID_SET_FILE_POINTER Then RaiseError HBF_SEEK_FAILURE End If End Sub Public Function WriteBytes(Buffer() As Byte) As Long RaiseErrorIfClosed If WriteFile(hFile, _ Buffer(LBound(Buffer)), _ UBound(Buffer) - LBound(Buffer) + 1, _ WriteBytes, _ 0) Then If fAutoFlush Then Flush Else RaiseError HBF_WRITE_FAILURE End If End Function Private Sub Class_Initialize() hFile = INVALID_HANDLE_VALUE End Sub Private Sub Class_Terminate() If hFile <> INVALID_HANDLE_VALUE Then CloseHandle hFile End Sub Private Sub RaiseError(ByVal ErrorCode As HBF_Errors) Dim Win32Err As Long, Win32Text As String Win32Err = Err.LastDllError If Win32Err Then Win32Text = vbNewLine & "Error " & Win32Err & vbNewLine _ & DecodeAPIErrors(Win32Err) End If If IsOpen Then CloseFile Select Case ErrorCode Case HBF_FILE_ALREADY_OPEN Err.Raise HBF_FILE_ALREADY_OPEN, HBF_SOURCE, _ "File already open." Case HBF_OPEN_FAILURE Err.Raise HBF_OPEN_FAILURE, HBF_SOURCE, _ "Error opening file." & Win32Text Case HBF_SEEK_FAILURE Err.Raise HBF_SEEK_FAILURE, HBF_SOURCE, _ "Seek Error." & Win32Text Case HBF_FILELEN_FAILURE Err.Raise HBF_FILELEN_FAILURE, HBF_SOURCE, _ "GetFileSize Error." & Win32Text Case HBF_READ_FAILURE Err.Raise HBF_READ_FAILURE, HBF_SOURCE, _ "Read failure." & Win32Text Case HBF_WRITE_FAILURE Err.Raise HBF_WRITE_FAILURE, HBF_SOURCE, _ "Write failure." & Win32Text Case HBF_FILE_ALREADY_CLOSED Err.Raise HBF_FILE_ALREADY_CLOSED, HBF_SOURCE, _ "File must be open for this operation." Case Else Err.Raise HBF_UNKNOWN_ERROR, HBF_SOURCE, _ "Unknown error." & Win32Text End Select End Sub Private Sub RaiseErrorIfClosed() If hFile = INVALID_HANDLE_VALUE Then RaiseError HBF_FILE_ALREADY_CLOSED End Sub Private Function DecodeAPIErrors(ByVal ErrorCode As Long) As String Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000& Dim strMsg As String, lngMsgLen As Long strMsg = Space$(256) lngMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0&, _ ErrorCode, 0&, strMsg, 256&, 0&) If lngMsgLen > 0 Then DecodeAPIErrors = Left(strMsg, lngMsgLen) Else DecodeAPIErrors = "Unknown Error." End If End Function
Option Explicit ' 'Timer-driven demo of HugeBinaryFile class. ' Private hbfFile As HugeBinaryFile Private blnWriting As Boolean Private bytBuf(1 To 1000000) As Byte Private lngBlocks As Long Private Const MAX_BLOCKS As Long = 5000 Private Sub cmdRead_Click() cmdWrite.Enabled = False cmdRead.Enabled = False lngBlocks = 0 lblRead.Caption = "" blnWriting = False Set hbfFile = New HugeBinaryFile hbfFile.OpenFile "test.dat" lblStatus = " Reading " _ & Format$(hbfFile.FileLen, "##,###,###,###,##0") _ & " bytes" Timer1.Enabled = True End Sub Private Sub cmdWrite_Click() cmdWrite.Enabled = False cmdRead.Enabled = False On Error Resume Next Kill "test.dat" On Error GoTo 0 lngBlocks = 0 lblWritten.Caption = "" lblStatus = " Writing " _ & Format$(CCur(MAX_BLOCKS) * CCur(UBound(bytBuf)), "##,###,###,###,##0") _ & " bytes" blnWriting = True Set hbfFile = New HugeBinaryFile hbfFile.OpenFile "test.dat" Timer1.Enabled = True End Sub Private Sub Form_Unload(Cancel As Integer) If Not (hbfFile Is Nothing) Then If hbfFile.IsOpen Then hbfFile.CloseFile Set hbfFile = Nothing End If End Sub Private Sub Timer1_Timer() If blnWriting Then hbfFile.WriteBytes bytBuf lngBlocks = lngBlocks + 1 lblWritten.Caption = _ Format$(CCur(lngBlocks) * CCur(UBound(bytBuf)), "##,###,###,###,##0") _ & " bytes written" If lngBlocks >= MAX_BLOCKS Then Timer1.Enabled = False hbfFile.CloseFile Set hbfFile = Nothing lblStatus = "" cmdWrite.Enabled = True cmdRead.Enabled = True End If Else hbfFile.ReadBytes bytBuf If hbfFile.EOF Then Timer1.Enabled = False hbfFile.CloseFile Set hbfFile = Nothing lblStatus = "" cmdWrite.Enabled = True cmdRead.Enabled = True Else lngBlocks = lngBlocks + 1 lblRead.Caption = _ Format$(CCur(lngBlocks) * CCur(UBound(bytBuf)), "##,###,###,###,##0") _ & " bytes read" End If End If End Sub
No comments:
Post a Comment