Get Size of Folder or File

Get size of folder or file

java.io.File file = new java.io.File("myfile.txt");
file.length();

This returns the length of the file in bytes or 0 if the file does not exist. There is no built-in way to get the size of a folder, you are going to have to walk the directory tree recursively (using the listFiles() method of a file object that represents a directory) and accumulate the directory size for yourself:

public static long folderSize(File directory) {
long length = 0;
for (File file : directory.listFiles()) {
if (file.isFile())
length += file.length();
else
length += folderSize(file);
}
return length;
}

WARNING: This method is not sufficiently robust for production use. directory.listFiles() may return null and cause a NullPointerException. Also, it doesn't consider symlinks and possibly has other failure modes. Use this method.

Get Folder Size from Windows Command Line

You can just add up sizes recursively (the following is a batch file):

@echo off
set size=0
for /r %%x in (folder\*) do set /a size+=%%~zx
echo %size% Bytes

However, this has several problems because cmd is limited to 32-bit signed integer arithmetic. So it will get sizes above 2 GiB wrong1. Furthermore it will likely count symlinks and junctions multiple times so it's at best an upper bound, not the true size (you'll have that problem with any tool, though).

An alternative is PowerShell:

Get-ChildItem -Recurse | Measure-Object -Sum Length

or shorter:

ls -r | measure -sum Length

If you want it prettier:

switch((ls -r|measure -sum Length).Sum) {
{$_ -gt 1GB} {
'{0:0.0} GiB' -f ($_/1GB)
break
}
{$_ -gt 1MB} {
'{0:0.0} MiB' -f ($_/1MB)
break
}
{$_ -gt 1KB} {
'{0:0.0} KiB' -f ($_/1KB)
break
}
default { "$_ bytes" }
}

You can use this directly from cmd:

powershell -noprofile -command "ls -r|measure -sum Length"

1 I do have a partially-finished bignum library in batch files somewhere which at least gets arbitrary-precision integer addition right. I should really release it, I guess :-)

Loop to pull file size, folder size, and directory size?

You can try to add all the informations in a dict and then convert it to dataframe.

  1. Collect all files information using os.wal and for each file:

    • Add and save the directory, file_name, file_size and file_date (as you did).
  2. Convert data into dataframe

  3. Group all directory and compute some aggregation function such count and sum.


Code

dir_path = Path(r'G:/OM/Permits')

# Collect data for all files in the directory
data = {'directory': [], 'file_name': [], 'file_size': [], 'file_date': []}
for dirpath, dirnames, filenames in os.walk(dir_path):
for f in filenames:
filename = "{}\{}" .format(dirpath, f)
data["directory"].append(dirpath)
data["file_name"].append(f)
data["file_size"].append(os.path.getsize(filename))
data["file_date"].append(time.strftime('%m/%d/%Y', time.gmtime(os.path.getmtime(filename))))

# Transform data in dataframe
files = pd.DataFrame(data)
print(files)

# details per folder:
folders_stats = files.groupby("directory").agg({"file_name": 'count',
"file_size": "sum"}) \
.rename(columns={"count": "total_files", "sum": "total_size"}) \
.reset_index()
print(folders_stats)

Fast(er) way to get folder size with batch script

After some testing and comparing the performance of

dir /s

compact /s

and powershell GetChild-Item

I found that using robocopy is much faster. One additional advantage is that even very long paths do not cause an error (> 256 characters in path), for instance in deeply nested folders.

And if you prefer to not count data behind junctions that can easily be included with robocopy like this:

@echo off
pushd "%~1" || goto :EOF

for /f "tokens=2 delims= " %%a in ('
robocopy "%CD%" "%TEMP%" /S /L /BYTES /XJ /NFL /NDL /NJH /R:0 ^| find "Bytes"
') do echo %CD%: %%a
popd

If you leave out the /BYTES option you'll get the size value formatted in MB or GB. One would have to print the dimension (k,m,g,t denoting kilo, mega, giga, tera) as well in this case, using another loop variable:

@echo off
setlocal ENABLEDELAYEDEXPANSION

pushd "%~1" || goto :EOF
set "folder=%CD%"
if NOT "%folder: =%"=="%folder%" set folder="%folder%"

for /f "tokens=2-3 delims= " %%a in (
'robocopy %folder% %folder% /S /L /XJ /NFL /NDL /NJH /R:0 ^| findstr /I "Bytes"'
) do (
set dim=%%b
set "dim=!dim:k=KB!" & set "dim=!dim:m=MB!" & set "dim=!dim:g=GB!" & set "dim=!dim:t=TB!"
if !dim! EQU %%b set dim=B
echo ^ %CD%: %%a !dim!
)
popd

The robocopy command here does not actually copy anything (due to the '/L' list option) but prints a summary line containing the sum of the filesizes which then is parsed. As robocopy still expects valid paths for the source and destination folders, the folder name is used twice.

The folder name may or may not contain spaces and thus eventually needs to be quoted. That is taken care of in the first lines.
%%b holds either the dimension letter or a numeric value. This is tested by substitution to avoid the 32bit limit of set /A.

Trying to get folder sizes for all users directory

The issue you have is that FullName contains a DirectoryInfo object, you have two options;

  1. Change your select to ExpandProperty which will change it to a string of the full path.

    Select-Object -ExpandProperty Fullname

  2. Refer to $Root using the property FullName which is a property on the DirectoryInfo Object.

    Get-ChildItem -path $Root.FullName -Recurse

This is one solution to what you are trying to achieve, note that errors (e.g. access denied) are ignored.

Get-ChildItem $StorageLocation | ForEach-Object {

$sizeInMB = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB

New-Object PSObject -Property @{
FullName = $_.FullName
SizeInMB = $sizeInMB
}
}


Related Topics



Leave a reply



Submit