Is there a way to output file size on disk in batch?
Asked Answered
G

3

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?

Gambeson answered 17/6, 2015 at 13:37 Comment(0)
S
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!

Scientistic answered 17/6, 2015 at 14:36 Comment(15)
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)Throe
Thanks Josef! I wasn't sure which value to use, as they're both the same on the system I'm on now.Scientistic
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 ).Throe
I took the lazy way of using wild cards. It's the same result. :)Scientistic
@Gambeson your batch will always be run on an English Windows ?Inhabitancy
@Inhabitancy Good point. I can do skip=8 to make it locale independent I think.Scientistic
I wouldn't look a hair-splitter, but skip=9 on my Win8,1Throe
@Throe 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?Scientistic
@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:\Varela
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.Scientistic
You may also calculate the space on disk in one line this way: set /a ondisk = ( (fs-1)/cluster+1 ) * clusterVarela
Yes. Your query outputs PCNAME,4096,C:\ however, I'd use rather wmic path win32_volume where "Caption='C:\\'" get BlockSize /value outputting BlockSize=4096Throe
Very well. All suggested changes implemented.Scientistic
@Aacini's suggestion is just a quick way to round up to the next multiple of blocksize. Unfortunately this won't work for resident filesNewmarket
since you're not actually getting the real file size on disk, it won't work for cases like NTFS compressed file or NFS files eitherNewmarket
I
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.

Inhabitancy answered 17/6, 2015 at 15:49 Comment(6)
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?Scientistic
@Scientistic 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.Inhabitancy
JosefZ suggested the same thing. I added the suggested change and just scrapped the entire fsutil method.Scientistic
@Scientistic Well done! You are the hero of the hour! Sorry for OT comment (deficient upvotes)Throe
@Inhabitancy 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}Scientistic
@Scientistic (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"Throe
S
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: [email protected] 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.

Swede answered 20/2, 2019 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.