I have a file on my hard drive that exceeds 2^31 bytes. LOF() cannot measure its exact size and errors out.
How can I measure its size to the exact byte using VB6 code? Any suggestions? :ehh:
Printable View
I have a file on my hard drive that exceeds 2^31 bytes. LOF() cannot measure its exact size and errors out.
How can I measure its size to the exact byte using VB6 code? Any suggestions? :ehh:
Perhaps this may help...
http://www.vbforums.com/showthread.p...ght=large+file
Good Luck
Code Doc, have you tried one of the solutions at that link? Especially post #2, function: API_FileSize, but gotta use API_OpenFile first to get a file handle and don't forget to close that handle when done.
VB cannot do this by itself. You will need APIs to read the huge file sizes. Pretty much all the examples about use the same code (some tweaked here and there).
Keith said, "VB cannot do this by itself. You will need APIs to read the huge file sizes."
----------------
What if I told you that I think typical VB6 code, without using an API crutch, can measure to within one byte on one passthrough on a file between 2^31 and 2 * 2^31 in size? Would anyone here believe me? :ehh:
My opinion only....
There are limitations to the (2147483648# * 2) + FileLen(largeFile) formula. Best to simply use one reliable method that works for all file sizes: APIs.
P.S. I never considered APIs a crutch. I believe without APIs and TLBs, VB would have died a long time ago.
OK, I admit that some APIs are great, even if many are poorly documented. Suppose we know that MyHugeFile exceeds 2^31 - 1 bytes. Take a look at this:
Sure, it might be slow, but will it work?Code:Private Sub Command1_Click()
Dim RNum As Long, FileSize As Currency, Buffer As String * 1
RNum = 2 ^ 31 - 1
FileSize = RNum - 1
Open "MyHugeFile" For Random As #1 Len = 1
Get #1, RNum, Buffer
Do Until EOF(1)
Get #1, , Buffer
FileSize = FileSize + 1
Loop
MsgBox "File Length = " & FileSize
End Sub
Have you tried FileLen?
I see no-one has commented on it since, so you've not really got much help. If you're hell-bent on not using APIs (I myself rarely do, I don't know most of them either) then I'd guess your code would work fine (I have no idea for definite and don't have a file large enough to test with :-P)...however, one slight speed improvement suggestion for you:
Rather than getting it to the exact byte, get it to the nearest 1MB first by setting the buffer size...when you have a basic idea then repeat it but get it to the nearest 1k then repeat again down to the nearest byte, each time using the starting point gained by the previous iteration. That way if it's 10GB larger than the max you haven't done 10*1024*1024*1024 iterations...instead, you've done a hell of a lot fewer (and test this out by counting the iterations with your method and this suggestion's method :-)).
I don't know figures, but I'm guessing you'd use exponentially fewer iterations to get the same result, and you could even add a GB iteration first if you KNOW the file is likely to be many gigabytes larger than the max filesize you start with. You could possibly also try making use of ON ERROR to try to access points within the file that are beyond the file's length and through process of elimination you'd eventually chance upon the filesize.
Just a few suggestions that I hope are of use, they're suggestions I'd try if I required what you're after :-)
Edit: If I can be bothered I could have a go at making a function for you that'd do it if you need help with it...give me an idea in gigabytes of the filesize you're working with so I can make space and generate a file to test with :-)
If you're willing to live with the loss of precision from scaling the value to a whole number Currency value you can use a single API call on the file by name. This example shows two ways to convert the size to a whole Currency value:
People often cringe at LSet, but it can be clearer and harder to screw up than using CopyMemory.Code:Option Explicit
Private Const GetFileExInfoStandard As Long = 0&
Private Type WIN32_FILE_ATTRIBUTE_DATA_SPECIAL
dwFileAttributes As Long
ftTimes(0 To 23) As Byte
nFileSizeHigh As Long
nFileSizeLow As Long
End Type
Private Type FLIP_CURR
nFileSizeLow As Long
nFileSizeHigh As Long
End Type
Private Type CURR_RESULT
Result As Currency
End Type
Private Declare Function GetFileAttributesEx Lib "kernel32" _
Alias "GetFileAttributesExW" ( _
ByVal lpFileName As Long, _
ByVal fInfoLevelId As Long, _
ByVal lpFileInformation As Long) As Long
Private Function FileSize1(ByVal FileName As String) As Currency
Dim FADS As WIN32_FILE_ATTRIBUTE_DATA_SPECIAL
Dim FC As FLIP_CURR
Dim RES As CURR_RESULT
If GetFileAttributesEx(StrPtr(FileName), GetFileExInfoStandard, VarPtr(FADS)) = 0 Then
Err.Raise Err.LastDllError, "FileSize", "System error"
Else
FC.nFileSizeLow = FADS.nFileSizeLow
FC.nFileSizeHigh = FADS.nFileSizeHigh
LSet RES = FC
FileSize1 = RES.Result * 10000@
End If
End Function
Private Function FileSize2(ByVal FileName As String) As Currency
Dim FADS As WIN32_FILE_ATTRIBUTE_DATA_SPECIAL
If GetFileAttributesEx(StrPtr(FileName), GetFileExInfoStandard, VarPtr(FADS)) = 0 Then
Err.Raise Err.LastDllError, "FileSize", "System error"
Else
FileSize2 = CCur(FADS.nFileSizeHigh) * 4294967296@ + CCur(FADS.nFileSizeLow)
End If
End Function
Private Sub Main()
MsgBox FileSize1("C:\Windows\notepad.exe")
MsgBox FileSize2("C:\Windows\notepad.exe")
End Sub
I will try your code immediately and report back as soon as I can. Thank you, D, for posting this possible solution.
If I can use Currency pointers to access the contents of this random access file, it suddenly becomes very useful to several of my Apps. :thumb:
I use this code to get space available on large drives with modification it could be used for file size:
http://www.developerfusion.com/code/...-large-drives/
Here's the FileSize() method in my XP library, which of course handles files >2gig. (As do all the drive size methods, obviously.) I'm not going to bother adding in hungarian notation, which I do not use in the XP library to make the interface more intuitive.This is about as fast and easy as it gets.vb Code:
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject 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 Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long ' Currency handles file sizes over 2 gig ' Thanks to Richard Newcombe from codeguru.com Public Function GetSize(ByVal File As String) As Currency Const GENERIC_READ = &H80000000 Const FILE_SHARE_READ = &H1 Const FILE_SHARE_WRITE = &H2 Const OPEN_EXISTING = 3 Dim lngHandle As Long Dim lngLow As Long Dim lngHigh As Long Dim curFileSize As Currency ' Open the file lngHandle = CreateFile(File, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0, 0) ' Get the file size lngLow = GetFileSize(lngHandle, lngHigh) CloseHandle lngHandle ' Combine the Low and High values into one currency ' Must use the '@' currency declaration or IDE will balk curFileSize = 4294967295@ * lngHigh If lngLow < 0 Then curFileSize = curFileSize + (4294967295@ + (lngLow + 1)) Else curFileSize = curFileSize + lngLow End If GetSize = curFileSize End Function