7

Is there a way to get the size on disk of a file like in the properties window:

I have tried:

(inside a batch file)

echo %~z1

,

for %i in (TestFile.txt) do echo %~zi

,

dir

But they only return the size of the file(s).

Is there any way to get the "size on disk" like the one seen in the properties window?

loadingnow
  • 597
  • 3
  • 20

3 Answers3

5

Interesting question. I'm not aware of the size on disk value being a property of any scriptable object. You could calculate it by getting filesize modulo bytes-per-cluster, subtracting that modulo from the file size, then adding the cluster size. (Edit: or use Aacini's more efficient calculation, which I'm still trying to understand.)

@echo off
setlocal

for %%I in (Testfile.txt) do (
    set "fs=%%~zI"
    for /f %%J in (
        'wmic volume where "driveletter='%%~dI'" get blocksize /value'
    ) do 2>nul set /a %%J
)

echo Size: %fs%

set /a ondisk = ((fs-1)/blocksize+1) * blocksize

echo Size on disk: %ondisk%

Many websites claim that fsutil fsinfo ntfsinfo DRIVE: is the best way to obtain the bytes per cluster. It seems that this method is fraught with peril, with different labels depending on locale and different number of lines for different versions of Windows. Additionally, as Marged says, fsutil requires elevation. This WMI method seems to work more universally, and without requiring admin rights.

Thanks JosefZ, Marged, and Aacini for all your input!

rojo
  • 24,000
  • 5
  • 55
  • 101
  • 2
    Use `Bytes Per Cluster` (e.g. 4096) rather than `Bytes Per Physical Sector` (e.g. 512). (Verified on my _tiny_ SSD). Then `set /a ondisk = (fs / clus +1)* clus)` – JosefZ Jun 17 '15 at 15:01
  • Thanks Josef! I wasn't sure which value to use, as they're both the same on the system I'm on now. – rojo Jun 17 '15 at 15:02
  • `findstr /i /C:"bytes per cluster"` note the `/C:` switch importance. Edit my previous comment: Then `set /a ondisk = (fs / clus +1) * clus` without trailing `)`. – JosefZ Jun 17 '15 at 15:06
  • 1
    I took the lazy way of using wild cards. It's the same result. :) – rojo Jun 17 '15 at 15:07
  • 1
    @loadingnow your batch will always be run on an English Windows ? – Marged Jun 17 '15 at 15:09
  • @Marged Good point. I can do `skip=8` to make it locale independent I think. – rojo Jun 17 '15 at 15:14
  • I wouldn't look a hair-splitter, but `skip=9` on my Win8,1 – JosefZ Jun 17 '15 at 15:27
  • @JosefZ on your *tiny* SSD, does `wmic path win32_volume get name,blocksize /format:csv | findstr /i "c:"` (where `c:` is the drive letter of your SSD) give you the appropriate bytes-per-cluster value? – rojo Jun 17 '15 at 15:54
  • 2
    @rojo: I am using Windows 8.1 Spanish. I need admin credentials to run `fsutil`, but it show the `Bytes por clúster: 4096` value at line 10 (skip=9). Your `wmic path win32_volume get name,blocksize /format:csv` correctly show the cluster size: COMPAQCQ45,4096,C:\ – Aacini Jun 17 '15 at 16:03
  • Thanks @Aacini! I take that as confirmation that the `wmic` method is more reliable / locale and Windows version agnostic than `fsutil`. I updated my answer accordingly. – rojo Jun 17 '15 at 16:09
  • 2
    You may also calculate the space on disk in one line this way: `set /a ondisk = ( (fs-1)/cluster+1 ) * cluster` – Aacini Jun 17 '15 at 16:12
  • 1
    Yes. Your query outputs `PCNAME,4096,C:\ ` however, I'd use rather `wmic path win32_volume where "Caption='C:\\'" get BlockSize /value` outputting `BlockSize=4096` – JosefZ Jun 17 '15 at 16:20
  • 1
    Very well. All suggested changes implemented. – rojo Jun 17 '15 at 16:24
  • @Aacini's suggestion is just a quick way to [round up to the next multiple of blocksize](https://stackoverflow.com/a/3407392/995714). Unfortunately [this won't work for resident files](https://i.imgur.com/sPcBmYp.png) – phuclv Jul 13 '18 at 02:08
  • since you're not actually getting the real file size on disk, it won't work for cases like [NTFS compressed file](https://i.imgur.com/ZrOfDpU.png) or NFS files either – phuclv Jul 13 '18 at 02:42
2

This is not intended to be an answer, just the values @rojo asked for:

NTFS-Volumeseriennummer             0xacf01e6ef01e3ed0
NTFS-Version :                           3.1
LFS-Version    :                  2.0
Anzahl der Sektoren :               0x000000000ed737ff
Gesamtzahl Cluster :                0x0000000001dae6ff
Freie Cluster :                     0x00000000008c8d41
Insgesamt reserviert :              0x0000000000000f70
Bytes pro Sektor  :                 512
Bytes pro physischem Sektor :       512
Bytes pro Cluster :                 4096
Bytes pro Dateidatensatzsegment   : 1024
Cluster pro Dateidatensatzsegment : 0
Gültige MFT-Datenlänge :            0x000000001c1c0000
MFT-Start-LCN  :                    0x00000000000c0000
MFT2-Start-LCN :                    0x0000000000000002
MFT-Zonenstart :                    0x00000000018a8ee0
MFT-Zonenende   :                   0x00000000018b12e0
Ressourcen-Manager-Bezeichner:        A81246B1-33B0-11E4-A94B-AEB4ABF863CB

This is from a German Windows 8.1. I think if it is necessary to make the batch locale independent you can not take the grepping approach. Instead scripting the appropriate filesystem object by using scripting host will be one solution.

The WMIC command has this result ...

SOMENAME,4096,C:\

... plus the advantage that I don't need to run this command with administrative rights.

Marged
  • 10,577
  • 10
  • 57
  • 99
  • Thank you Marged. As long as you're willing to be my henchman, can you run `wmic path win32_volume get name,blocksize /format:csv | findstr /i "c:"` and tell me whether the value returned includes 4096? – rojo Jun 17 '15 at 15:59
  • @rojo updated my answer and as expected this works for German Windows too. Perhaps it is somehow possible to add a 'where name=C:' or similar to the wmic query. Although your script is great I think this is a borderline case where one might think of switching from batches to improved scripting. – Marged Jun 17 '15 at 16:18
  • JosefZ suggested the same thing. I added the suggested change and just scrapped the entire `fsutil` method. – rojo Jun 17 '15 at 16:29
  • @rojo Well done! You are the hero of the hour! Sorry for _OT_ comment (deficient upvotes) – JosefZ Jun 17 '15 at 16:49
  • @Marged improved scripting such as `powershell "$f = gi Testfile.txt; $s = $f.Length; $d = $f.FullName.split('\')[0]; 'Size: '+$s; gwmi win32_volume | where { $_.caption -match $d } | select blocksize | % {$b = $_.blocksize}; $o = [int](($s - 1) / $b + 1) * $b; 'Size on disk: '+$o"` you mean? *{grin}* – rojo Jun 17 '15 at 17:05
  • @rojo (maybe with some superabundant parentheses) `powershell "$f = gi Testfile.txt; $s = $f.Length; $d = $f.FullName.split('\')[0]; 'Size: '+$s; gwmi win32_volume | where { $_.caption -match $d } | select blocksize | % {$b = $_.blocksize}; $o = ([math]::truncate(($s - 1) / $b) + 1) * $b; 'Size on disk: '+$o"` – JosefZ Jun 17 '15 at 17:30
1

Looking for an answer to the same question, I just found this :
http://www.ltr-data.se/opencode.html/
The sizeof tool does just that.

sizeof, freeware by Olof Lagerkvist. http://www.ltr-data.se e-mail: olof@ltr-data.se More info, including distribution permissions and source code is available on the website.

This tool displays the total allocation size on disk for files and directories.

Command line syntax: sizeof [-xo] [-presentation] file1 [file2 ...]

-x Do not follow junctions or other reparse points. This makes sure that sizeof stays within the filesystem where it starts searching.

-o Include sizes of offline files.

-c Count and display number of files in each found directory, instead of count and display sizes of them.

The presentation determines in which format to display the sizes of files and directories. The argument can be any of the following:

-b Number of 512-byte blocks. -h Human readable format. -k Kilobytes. -m Megabytes. -g Gigabytes. -t Terabytes.

It's better than some other solutions proposed on this page as it provides the correct “size on disk” (which by the way should be renamed to “size on partition” or “size on storage device” as nowadays many storage devices are not “disks”) for compressed or sparse files. I precisely wanted to compare the effect of NTFS compression and “sparseness” for a bunch of large files which are partial downloads from a file sharing software; so I'm going to first use sizeof to get the actual allocated size of those files which are currently compressed, then I'm going to uncompress them, then convert them to “sparse”, then run sizeof again.

I've only found one utility which can convert a non-sparse file to sparse, and actually de-allocate its empty sectors : a command line tool called SparseTest, which was released more than 10 years ago, “for demo purposes only”, and seems to have vanished long ago, but is still available there :
https://web.archive.org/web/20151103231305if_/http://pages.infinit.net/moonligh/eMule/Releases/SparseTest.zip

SparseTest also displays the “size on disk” before applying the “sparse” attribute (but the output is more complex so it wouldn't be easy to use in a batch script if that information is needed for a further purpose). It calculates a checksum before and after to ensure that the file's integrity was preserved in the process (I'd still recommand to make a backup first, and verifying that all files are strictly identical afterwards with another tool, like WinMerge or MD5Checker). Contrary to files with the “C” attribute, which appear in blue color, nothing distinguishes “sparse” files from regular files, except the “P” in the Attributes column (and it does not even appear in the Properties).

The native Windows tool fsutil can set the sparse attribute, but it does not actually compress the file, its “size on disk” remains unchanged even if it contains a lot of empty sectors; only if the file size is later increased with empty sectors will they be added in a “sparse” manner, i.e. stored as metadata and not actually allocated.

GabrielB
  • 141
  • 4