Skip to content

Commit e1f43cc

Browse files
authored
Feature: Added "Size on disk" property to the Properties window (#12777)
1 parent 55df97d commit e1f43cc

File tree

9 files changed

+130
-19
lines changed

9 files changed

+130
-19
lines changed

src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ public string ItemSize
147147
set => SetProperty(ref itemSize, value);
148148
}
149149

150+
private string itemSizeOnDisk;
151+
public string ItemSizeOnDisk
152+
{
153+
get => itemSizeOnDisk;
154+
set => SetProperty(ref itemSizeOnDisk, value);
155+
}
156+
150157
private string uncompresseditemSize;
151158
public string UncompressedItemSize
152159
{
@@ -179,6 +186,13 @@ public long ItemSizeBytes
179186
set => SetProperty(ref itemSizeBytes, value);
180187
}
181188

189+
private long itemSizeOnDiskBytes;
190+
public long ItemSizeOnDiskBytes
191+
{
192+
get => itemSizeOnDiskBytes;
193+
set => SetProperty(ref itemSizeOnDiskBytes, value);
194+
}
195+
182196
private long uncompresseditemSizeBytes;
183197
public long UncompressedItemSizeBytes
184198
{
@@ -193,6 +207,13 @@ public bool ItemSizeProgressVisibility
193207
set => SetProperty(ref itemSizeProgressVisibility, value);
194208
}
195209

210+
private bool itemSizeOnDiskProgressVisibility = false;
211+
public bool ItemSizeOnDiskProgressVisibility
212+
{
213+
get => itemSizeOnDiskProgressVisibility;
214+
set => SetProperty(ref itemSizeOnDiskProgressVisibility, value);
215+
}
216+
196217
// For libraries
197218
public int locationsCount;
198219
public int LocationsCount

src/Files.App/Helpers/Interop/NativeFileOperationsHelper.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,21 @@ public static bool WriteBufferToFileWithProgress(string filePath, byte[] buffer,
478478
return null;
479479
}
480480

481+
public static long? GetFileSizeOnDisk(string filePath)
482+
{
483+
using var handle = OpenFileForRead(filePath);
484+
if (!handle.IsInvalid)
485+
{
486+
try
487+
{
488+
var fileAllocationInfo = Kernel32.GetFileInformationByHandleEx<Kernel32.FILE_STANDARD_INFO>(handle, Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo);
489+
return fileAllocationInfo.AllocationSize;
490+
}
491+
catch { }
492+
}
493+
return null;
494+
}
495+
481496
// https://github.com/rad1oactive/BetterExplorer/blob/master/Windows%20API%20Code%20Pack%201.1/source/WindowsAPICodePack/Shell/ReparsePoint.cs
482497
public static string ParseSymLink(string path)
483498
{

src/Files.App/Strings/en-US/Resources.resw

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@
138138
<data name="SizeLabel" xml:space="preserve">
139139
<value>Size:</value>
140140
</data>
141+
<data name="SizeOnDiskLabel" xml:space="preserve">
142+
<value>Size on disk:</value>
143+
</data>
141144
<data name="UncompressedSize" xml:space="preserve">
142145
<value>Uncompressed Size:</value>
143146
</data>

src/Files.App/ViewModels/Properties/Items/BaseProperties.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,17 @@ public async Task GetOtherProperties(IStorageItemExtraProperties properties)
3939
ViewModel.ItemAccessedTimestamp = dateTimeFormatter.ToShortLabel((DateTimeOffset)(extraProperties[dateAccessedProperty] ?? DateTimeOffset.Now));
4040
}
4141

42-
public async Task<long> CalculateFolderSizeAsync(string path, CancellationToken token)
42+
public async Task<(long size, long sizeOnDisk)> CalculateFolderSizeAsync(string path, CancellationToken token)
4343
{
4444
if (string.IsNullOrEmpty(path))
4545
{
4646
// In MTP devices calculating folder size would be too slow
4747
// Also should use StorageFolder methods instead of FindFirstFileExFromApp
48-
return 0;
48+
return (0, 0);
4949
}
5050

5151
long size = 0;
52+
long sizeOnDisk = 0;
5253
FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
5354
int additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
5455

@@ -72,24 +73,30 @@ public async Task<long> CalculateFolderSizeAsync(string path, CancellationToken
7273
if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
7374
{
7475
size += findData.GetSize();
76+
var fileSizeOnDisk = NativeFileOperationsHelper.GetFileSizeOnDisk(Path.Combine(path, findData.cFileName));
77+
sizeOnDisk += fileSizeOnDisk ?? 0;
7578
++count;
7679
ViewModel.FilesCount++;
7780
}
7881
else if (findData.cFileName != "." && findData.cFileName != "..")
7982
{
8083
var itemPath = Path.Combine(path, findData.cFileName);
8184

82-
size += await CalculateFolderSizeAsync(itemPath, token);
85+
var folderSize = await CalculateFolderSizeAsync(itemPath, token);
86+
size += folderSize.size;
87+
sizeOnDisk += folderSize.sizeOnDisk;
8388
++count;
8489
ViewModel.FoldersCount++;
8590
}
8691

87-
if (size > ViewModel.ItemSizeBytes)
92+
if (size > ViewModel.ItemSizeBytes || sizeOnDisk > ViewModel.ItemSizeOnDiskBytes)
8893
{
8994
await Dispatcher.EnqueueOrInvokeAsync(() =>
9095
{
9196
ViewModel.ItemSizeBytes = size;
9297
ViewModel.ItemSize = size.ToSizeString();
98+
ViewModel.ItemSizeOnDiskBytes = sizeOnDisk;
99+
ViewModel.ItemSizeOnDisk = sizeOnDisk.ToSizeString();
93100
SetItemsCountString();
94101
},
95102
DispatcherQueuePriority.Low);
@@ -102,11 +109,11 @@ await Dispatcher.EnqueueOrInvokeAsync(() =>
102109

103110
FindClose(hFile);
104111

105-
return size;
112+
return (size, sizeOnDisk);
106113
}
107114
else
108115
{
109-
return 0;
116+
return (0, 0);
110117
}
111118
}
112119

src/Files.App/ViewModels/Properties/Items/CombinedProperties.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,13 @@ public override async Task GetSpecialProperties()
7272
long totalSize = 0;
7373
long filesSize = List.Where(x => x.PrimaryItemAttribute == StorageItemTypes.File).Sum(x => x.FileSizeBytes);
7474
long foldersSize = 0;
75+
long totalSizeOnDisk = 0;
76+
long filesSizeOnDisk = List.Where(x => x.PrimaryItemAttribute == StorageItemTypes.File)
77+
.Sum(x => NativeFileOperationsHelper.GetFileSizeOnDisk(x.ItemPath) ?? 0);
78+
long foldersSizeOnDisk = 0;
7579

7680
ViewModel.ItemSizeProgressVisibility = true;
81+
ViewModel.ItemSizeOnDiskProgressVisibility = true;
7782

7883
foreach (var item in List)
7984
{
@@ -88,7 +93,9 @@ public override async Task GetSpecialProperties()
8893

8994
try
9095
{
91-
foldersSize += await fileSizeTask;
96+
var folderSize = await fileSizeTask;
97+
foldersSize += folderSize.size;
98+
foldersSizeOnDisk += folderSize.sizeOnDisk;
9299
}
93100
catch (Exception ex)
94101
{
@@ -98,9 +105,12 @@ public override async Task GetSpecialProperties()
98105
}
99106

100107
ViewModel.ItemSizeProgressVisibility = false;
108+
ViewModel.ItemSizeOnDiskProgressVisibility = false;
101109

102110
totalSize = filesSize + foldersSize;
103111
ViewModel.ItemSize = totalSize.ToLongSizeString();
112+
totalSizeOnDisk = filesSizeOnDisk + foldersSizeOnDisk;
113+
ViewModel.ItemSizeOnDisk = totalSizeOnDisk.ToLongSizeString();
104114

105115
SetItemsCountString();
106116
}

src/Files.App/ViewModels/Properties/Items/FileProperties.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ public override async Task GetSpecialProperties()
9797

9898
ViewModel.ItemSizeVisibility = true;
9999
ViewModel.ItemSize = Item.FileSizeBytes.ToLongSizeString();
100+
ViewModel.ItemSizeOnDisk = NativeFileOperationsHelper.GetFileSizeOnDisk(Item.ItemPath)?.ToLongSizeString() ??
101+
string.Empty;
100102

101103
var fileIconData = await FileThumbnailHelper.LoadIconFromPathAsync(Item.ItemPath, 80, Windows.Storage.FileProperties.ThumbnailMode.DocumentsView, false);
102104
if (fileIconData is not null)

src/Files.App/ViewModels/Properties/Items/FolderProperties.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public async override Task GetSpecialProperties()
8989
{
9090
ViewModel.ItemSizeVisibility = true;
9191
ViewModel.ItemSize = Item.FileSizeBytes.ToLongSizeString();
92+
var sizeOnDisk = NativeFileOperationsHelper.GetFileSizeOnDisk(Item.ItemPath);
93+
if (sizeOnDisk is not null)
94+
{
95+
ViewModel.ItemSizeOnDisk = ((long)sizeOnDisk).ToLongSizeString();
96+
}
9297
ViewModel.ItemCreatedTimestamp = Item.ItemDateCreated;
9398
ViewModel.ItemAccessedTimestamp = Item.ItemDateAccessed;
9499
if (Item.IsLinkItem || string.IsNullOrWhiteSpace(((ShortcutItem)Item).TargetPath))
@@ -123,6 +128,7 @@ public async override Task GetSpecialProperties()
123128
{
124129
ViewModel.ItemSizeVisibility = false;
125130
}
131+
ViewModel.ItemSizeOnDisk = string.Empty;
126132
if (recycleBinQuery.NumItems is long numItems)
127133
{
128134
ViewModel.FilesCount = (int)numItems;
@@ -156,6 +162,7 @@ private async Task GetFolderSize(string folderPath, CancellationToken token)
156162

157163
ViewModel.ItemSizeVisibility = true;
158164
ViewModel.ItemSizeProgressVisibility = true;
165+
ViewModel.ItemSizeOnDiskProgressVisibility = true;
159166

160167
var fileSizeTask = Task.Run(async () =>
161168
{
@@ -166,15 +173,18 @@ private async Task GetFolderSize(string folderPath, CancellationToken token)
166173
try
167174
{
168175
var folderSize = await fileSizeTask;
169-
ViewModel.ItemSizeBytes = folderSize;
170-
ViewModel.ItemSize = folderSize.ToLongSizeString();
176+
ViewModel.ItemSizeBytes = folderSize.size;
177+
ViewModel.ItemSize = folderSize.size.ToLongSizeString();
178+
ViewModel.ItemSizeOnDiskBytes = folderSize.sizeOnDisk;
179+
ViewModel.ItemSizeOnDisk = folderSize.sizeOnDisk.ToLongSizeString();
171180
}
172181
catch (Exception ex)
173182
{
174183
App.Logger.LogWarning(ex, ex.Message);
175184
}
176185

177186
ViewModel.ItemSizeProgressVisibility = false;
187+
ViewModel.ItemSizeOnDiskProgressVisibility = false;
178188

179189
SetItemsCountString();
180190
}

src/Files.App/ViewModels/Properties/Items/LibraryProperties.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,23 +112,30 @@ private async Task GetLibrarySize(List<BaseStorageFolder> storageFolders, Cancel
112112
{
113113
ViewModel.ItemSizeVisibility = true;
114114
ViewModel.ItemSizeProgressVisibility = true;
115+
ViewModel.ItemSizeOnDiskProgressVisibility = true;
115116

116117
try
117118
{
118119
long librarySize = 0;
120+
long librarySizeOnDisk = 0;
119121
foreach (var folder in storageFolders)
120122
{
121-
librarySize += await Task.Run(async () => await CalculateFolderSizeAsync(folder.Path, token));
123+
var foldersSize = await Task.Run(async () => await CalculateFolderSizeAsync(folder.Path, token));
124+
librarySize += foldersSize.size;
125+
librarySizeOnDisk += foldersSize.sizeOnDisk;
122126
}
123127
ViewModel.ItemSizeBytes = librarySize;
124128
ViewModel.ItemSize = librarySize.ToLongSizeString();
129+
ViewModel.ItemSizeOnDiskBytes = librarySize;
130+
ViewModel.ItemSizeOnDisk = librarySize.ToLongSizeString();
125131
}
126132
catch (Exception ex)
127133
{
128134
App.Logger.LogWarning(ex, ex.Message);
129135
}
130136

131137
ViewModel.ItemSizeProgressVisibility = false;
138+
ViewModel.ItemSizeOnDiskProgressVisibility = false;
132139

133140
SetItemsCountString();
134141
}

0 commit comments

Comments
 (0)