How can I retrieve a files Size On Disk from Windows?

marlan

Registered User.
Local time
Today, 04:28
Joined
Jan 19, 2010
Messages
414
Hi,
We've received a user request to save on DB, and display on a form , some file's Size On disk, as displayed in Windows browser.
the
Code:
FileLen()
function returns the file size, without the Winnows (or NTFS) overhead.

assuming this info is used a lot in windows, is it saved any ware? can it be retrieved?
otherwise: how can it be calculated?
1722773399431.png


TIA
 
One point - the Size returned by Extended File properties "Size" and "Total size" are in the abbreviated format '446 GB' etc, whereas the FSO 'size' property of a FSO file is in full numeric format eg, 58,520,161.

Actual examples:

FSO
? FileSize("\\WDMyCloud\Public\AddressBook\AddressBE.accdb")
1011712

File properties

? GetFileProperty("\\WDMyCloud\Public\AddressBook\AddressBE.accdb","Size")
988 KB

A simple function to do the biz with FSO.

Code:
Public Function FileSize(pstrPath As String) As Double
    Static fso As New Scripting.FileSystemObject
    Dim fle As Scripting.File
    If fso.FileExists(pstrPath) Then
        Set fle = fso.GetFile(pstrPath)
        FileSize = fle.Size
    Else
        FileSize = -1
    End If

Notice fso is declared as static so it only instantiates on the first call.
 
Last edited:
DickyP is correct and has offered a couple of great examples. Something DOES need explaining, though.

When a file says its size (using fso's .SIZE property) is 58,520,161 bytes, that takes into account that part of the file header includes the number of file bytes occupied in the last block of the file, i.e. the position of the "true" end of the file, even though it might not fill up that last block - particularly for text files, but also for other file types. Therefore, the number of bytes does NOT have to be an even number.

Because of something called a disk allocation unit, the file's physical size on disk will include some amount of empty ("slack") space at the end. Decide whether you care about that because there are easy ways to figure out actual "allocated" space (with FSO, for example) if you know file size and disk allocation unit size. In older documentation, a disk allocation unit is sometimes called a "disk cluster." The size of the allocation unit is usually defined when you initialize a new (virgin) disk. With NTFS volumes, common cluster sizes are 4kb, 8kb, or (rarely) 16kb. You don't usually do disk initialization when you buy a pre-configured machine, but if you are a do-it-yourself type, you would run into this option.
 
When a file says its size (using fso's .SIZE property) is 58,520,161 bytes, that takes into account that part of the file header includes the number of file bytes occupied in the last block of the file, i.e. the position of the "true" end of the file, even though it might not fill up that last block - particularly for text files, but also for other file types. Therefore, the number of bytes does NOT have to be an even number.
Probably a good job we don't normally require that level of exactitude :)
 
Just as a follow-up.

If you wanted to see specifics about your drive's cluster size, run the CMD prompt AS ADMIN. The old DOS-style utilities use the word CLUSTER rather than ALLOCATION UNIT but they mean the same thing. Allocation units are sized to allow you to write several disk blocks (1 block=512 bytes) into a single cluster of some number of blocks without having to allocate a new storage unit quite so often. Cluster size is a balancing act between the number of sectors (disk blocks) and the frequency of allocating new sectors when you are creating files. The OTHER balancing act is that smaller clusters allow you to have more small files, where larger clusters would be what you use if you anticipate having a smaller number of very large files. If you have a dedicated database disk for a package like ORACLE or SQL SERVER or several other SQL engine servers, the "small number of large files" option is popular. Your system disk, however, should ALWAYS be "large number of smaller files."

C:\WINDOWS\system32>fsutil fsinfo ntfsinfo c:
Code:
NTFS Volume Serial Number :        0xc074ba0774ba0068
NTFS Version      :                3.1
LFS Version       :                2.0
Total Sectors     :                1,999,218,687  (953.3 GB)
Total Clusters    :                  249,902,335  (953.3 GB)
Free Clusters     :                  158,650,450  (605.2 GB)
Total Reserved Clusters :              1,309,085  (  5.0 GB)
Reserved For Storage Reserve :         1,297,916  (  5.0 GB)
Bytes Per Sector  :                512
Bytes Per Physical Sector :        512
Bytes Per Cluster :                4096                      <=====
Bytes Per FileRecord Segment    :  1024
Clusters Per FileRecord Segment :  0
Mft Valid Data Length :            1.11 GB
Mft Start Lcn  :                   0x00000000000c0000
Mft2 Start Lcn :                   0x0000000000000002
Mft Zone Start :                   0x000000000470caa0
Mft Zone End   :                   0x00000000047188e0
MFT Zone Size  :                   190.25 MB
Max Device Trim Extent Count :     512
Max Device Trim Byte Count :       0xffffffff
Max Volume Trim Extent Count :     62
Max Volume Trim Byte Count :       0x40000000
Resource Manager Identifier :      04F75F30-F435-11E9-8C8C-8642FC35101D
 
Hi, and thanks for your replies!
FSO
? FileSize("\\WDMyCloud\Public\AddressBook\AddressBE.accdb")
1011712

File properties

? GetFileProperty("\\WDMyCloud\Public\AddressBook\AddressBE.accdb","Size")
988 KB

Code:
Public Function FileSize(pstrPath As String) As Double
    Static fso As New Scripting.FileSystemObject
    Dim fle As Scripting.File
    If fso.FileExists(pstrPath) Then
        Set fle = fso.GetFile(pstrPath)
        FileSize = fle.Size
    Else
        FileSize = -1
    End If
I wrote this access VBA code, that results wrong for me:
Code:
Public Function SizeOnDisk(pstrPath As String) As Double
    Static fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject") ' Set fso = New Scripting.FileSystemObject - will not compile
    'Dim fle As Object
    If fso.FileExists(pstrPath) Then
        'Set fle = fso.GetFile(pstrPath)
        SizeOnDisk = fso.GetFileProperty(pstrPath, "Size") 'Here I get "Object doesn't support this property or method" error
    Else
        SizeOnDisk = -1
    End If
End Function
What am I doing wrong? any references I'm missing?
 
Just as a follow-up.

If you wanted to see specifics about your drive's cluster size, run the CMD prompt AS ADMIN. The old DOS-style utilities use the word CLUSTER rather than ALLOCATION UNIT but they mean the same thing. Allocation units are sized to allow you to write several disk blocks (1 block=512 bytes) into a single cluster of some number of blocks without having to allocate a new storage unit quite so often. Cluster size is a balancing act between the number of sectors (disk blocks) and the frequency of allocating new sectors when you are creating files. The OTHER balancing act is that smaller clusters allow you to have more small files, where larger clusters would be what you use if you anticipate having a smaller number of very large files. If you have a dedicated database disk for a package like ORACLE or SQL SERVER or several other SQL engine servers, the "small number of large files" option is popular. Your system disk, however, should ALWAYS be "large number of smaller files."

C:\WINDOWS\system32>fsutil fsinfo ntfsinfo c:
Code:
NTFS Volume Serial Number :        0xc074ba0774ba0068
NTFS Version      :                3.1
LFS Version       :                2.0
Total Sectors     :                1,999,218,687  (953.3 GB)
Total Clusters    :                  249,902,335  (953.3 GB)
Free Clusters     :                  158,650,450  (605.2 GB)
Total Reserved Clusters :              1,309,085  (  5.0 GB)
Reserved For Storage Reserve :         1,297,916  (  5.0 GB)
Bytes Per Sector  :                512
Bytes Per Physical Sector :        512
Bytes Per Cluster :                4096                      <=====
Bytes Per FileRecord Segment    :  1024
Clusters Per FileRecord Segment :  0
Mft Valid Data Length :            1.11 GB
Mft Start Lcn  :                   0x00000000000c0000
Mft2 Start Lcn :                   0x0000000000000002
Mft Zone Start :                   0x000000000470caa0
Mft Zone End   :                   0x00000000047188e0
MFT Zone Size  :                   190.25 MB
Max Device Trim Extent Count :     512
Max Device Trim Byte Count :       0xffffffff
Max Volume Trim Extent Count :     62
Max Volume Trim Byte Count :       0x40000000
Resource Manager Identifier :      04F75F30-F435-11E9-8C8C-8642FC35101D
Is there a way to get this Information using VBA?
 
Is there a way to get this Information using VBA?

Using pure vba to find file size on disk :
Code:
Public Function SizeOnDisk(pstrPath As String) As Long
    
    SizeOnDisk = FileLen(pstrPath)

End Function



Using FSO to find file size on disk: ( It's called early binding. It means you have to add a reference to Microsoft Scripting Runtime
(Tools --> References)
Code:
Public Function SizeOnDisk(pstrPath As String) As Long
 
    Dim FSO As New Scripting.FileSystemObject
    Dim f As File
    
    Set f = FSO.GetFile(pstrPath)
    SizeOnDisk = f.SIZE
 
End Function



the following is the same as above. Uses FSO, but it's late binding. Means you don't need any references to Microsoft Scripting Runtime
Code:
Public Function SizeOnDisk(pstrPath As String) As Long
 
    Dim fso As Object
    Dim f As Object
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set f = fso.GetFile(pstrPath)
 
    SizeOnDisk = f.SIZE
    
End Function
 
Hi, and thanks for your replies!

I wrote this access VBA code, that results wrong for me:
Code:
Public Function SizeOnDisk(pstrPath As String) As Double
    Static fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject") ' Set fso = New Scripting.FileSystemObject - will not compile
    'Dim fle As Object
    If fso.FileExists(pstrPath) Then
        'Set fle = fso.GetFile(pstrPath)
        SizeOnDisk = fso.GetFileProperty(pstrPath, "Size") 'Here I get "Object doesn't support this property or method" error
    Else
        SizeOnDisk = -1
    End If
End Function
What am I doing wrong? any references I'm missing?
You aren't doing anything wrong. You are trying to mix two different things.

I forgot to say that GetFileProperty() is a separate function which I didn't supply the code for as I consider it too clumsy, for this task. I only ever use it to get graphics dimensions.

I can supply the code if wanted - I found it on the Internet so I can't claim any wizardry. As written it reinstates a new shell process on every call so not good for bulk usage.
 
Last edited:
Why not see how @isladogs does it? in post #2 ?
I do not think you can get size on disk without calculation, as I did not see in in @isladogs db example.
You would have to see the cluster size and calculate accordingly as @The_Doc_Man has mentioned.

1722850654176.png
 
Last edited:
It should also be noted that, at least on NTFS volumes, very small files may be stored directly in the MFT and therefore do not occupy a single extra cluster:

Those assumptions don't hold true for NTFS—not even the “file contents are stored in units of clusters” part. In NTFS, a file can actually consume zero clusters for its data by stashing itself into slack space in the master file table (MFT)
See Windows Confidential: Just What Is ‘Size on Disk’? and/or How can a file's size on disk be 0 bytes when there's data in it?
 
One nuance I hadn't thought of when trying to help on this topic is of course the size on disc requirement - this of course is not constant and differs from PC to PC according to its configuration. I'd like to see the usage intended for it.
 
@DickyP :
I suspect the preliminary check whether files/folders fit on another medium/volume.
I had a similar issue decades ago.
 
Is there a way to get this Information using VBA?


I get the following and I am Administrator on this laptop

When you launch the CMD prompt, you must remember to RUN AS ADMIN or you will get that "denied" error message. I'm an admin on my home system but some things automagically assume you meant "RUN AS JoeSchmuckatelli\Users" and then they block you from getting to the good stuff.
 
Doc, just adding \ makes it work regardless. :)
That is because I have the cmd prompt on my taskbar, and there is no option for Adminitrator as you can get with a shortcut on the desktop.
 
Last edited:
Why not see how @isladogs does it? in post #2 ?

Whilst Extended File Properties are very powerful, their use is overkill if just the file size is required.
You don't even need to use FSO or add additional references
This is all the code needed to get the file size in kilobytes =:

Rich (BB code):
Function GetFileSize(strFilePath As String)

 On Error GoTo Err_Handler
 
    Dim lngFileSize As Long

    'file size in kilobytes
    lngFileSize = FileLen(strFilePath) 'bytes
    GetFileSize = lngFileSize / 1024 'kilobytes

Exit_Handler:
    Exit Function

Err_Handler:
    If Err = 53 Then Exit Function 'file not found
    If Err = 76 Then Exit Function 'path not found
    MsgBox "Error " & Err.Number & " in GetFileSize procedure: " & Err.Description
    Resume Exit_Handler:

End Function

Example usage from Immediate window:
Code:
?GetFileSize("G:\MyFiles\ImageIconTest.accdb")
 408

EDIT:
Just noticed @KitaYama gave this code in post #9
 
Doc, just adding \ makes it work regardless. :)
That is because I have the cmd prompt on my taskbar, and there is no option for Adminitrator as you can get with a shortcut on the desktop.
Yes there is - when you right-click on it on the task bar and the options of Command Prompt and Unpin from Task Bar appear , Right-Click on 'Command Prompt' and choose the Run As Administrator option. This is standard taskbar behaviour.

1722876813336.jpeg
 
Last edited:

Users who are viewing this thread

Back
Top Bottom