我正在嘗試計算檔案夾大小,但問題是;它在 D:\ 驅動器或其他檔案夾中運行速度很快,但是每當我嘗試單擊 C:\ 驅動器時,應用程式都會凍結大約 7-8 秒。(我的驅動器串列在樹視圖上)當我洗掉檔案夾大小時,一切正常。你們有什么想法嗎?
public FolderModel(string folderPath)
{
try
{
//File = new FileInfo(folderPath);
//FolderInfo = new DirectoryInfo(folderPath);
//_createdTime = FolderInfo.CreationTime.ToShortDateString();
//_folderName = FolderInfo.Name;
//_folderPath = folderPath;
//Fileextension = File.Extension.ToLower();
//this.Children = new ObservableCollection<FolderModel>();
_folderSize = CalculatorSize(GetDirectorySize(folderPath));
}
catch (Exception e)
{
//
}
}
internal string CalculatorSize(long bytes)
{
var suffix = new[] { "B", "KB", "MB", "GB", "TB" };
float byteNumber = bytes;
for (var i = 0; i < suffix.Length; i )
{
if (byteNumber < 1000)
{
if (i == 0)
return $"{byteNumber} {suffix[i]}";
else
return $"{byteNumber:0.#0} {suffix[i]}";
}
else
{
byteNumber /= 1024;
}
}
return $"{byteNumber:N} {suffix[suffix.Length - 1]}";
}
internal static long GetDirectorySize(string directoryPath)
{
try
{
if (Directory.Exists(directoryPath))
{
var d = new DirectoryInfo(directoryPath);
return d.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}
return new FileInfo(directoryPath).Length;
}
catch (UnauthorizedAccessException)
{
return 0;
}
catch (FileNotFoundException)
{
return 0;
}
catch (DirectoryNotFoundException)
{
return 0;
}
}
uj5u.com熱心網友回復:
您必須在后臺執行緒上列舉檔案夾。
性能提升建議
使用DriveInfoAPI 時,您可以進一步提高檔案夾路徑為驅動器的情況下的性能。在這種情況下,您可以省略整個驅動器的列舉,這通常需要一段時間。
此外,當列舉引發UnauthorizedAccessException例外時,您當前的實作會中止計算。你不想那樣。您希望演算法忽略禁止的檔案系統路徑。
以下兩個示例顯示了您的實作的固定和改進版本。
第一個解決方案針對現代 .NET Standard 2.1 兼容的 .NET 版本。
第二個解決方案針對舊的 .NET Framework。
.NET 標準 2.1(.NET Core 3.0、.NET 5)
當使用與 .NET Standard 2.1 兼容的 .NET 版本(如 .NET Core 3.0 和 .NET 5)時,您可以消除例外處理。使用EnumerationOptions作為引數允許API忽略無法訪問的目錄,其中顯著提高性能(沒有更多的UnauthorizedAccessException例外)和可讀性:
internal static async Task<bool> TryGetDirectorySize(string directoryPath, out long spaceUsedInBytes)
{
spaceUsedInBytes = -1;
var drives = DriveInfo.GetDrives();
DriveInfo targetDrive = drives.FirstOrDefault(drive => drive.Name.Equals(directoryPath, StringComparison.OrdinalIgnoreCase));
// Directory is a drive: skip the expensive enumeration of complete drive.
if (targetDrive != null)
{
spaceUsedInBytes = targetDrive.TotalSize - targetDrive.TotalFreeSpace;
return true;
}
if (!Directory.Exists(folderPath))
{
return false;
}
// Consider to make this local variable a private property
var enumerationOptions = new EnumerationOptions { RecurseSubdirectories = true };
var targetFolderInfo = new DirectoryInfo(directoryPath);
spaceUsedInBytes = await Task.Run(
() => targetFolderInfo.EnumerateFiles("*", enumerationOptions)
.Sum(fileInfo => fileInfo.Length));
return true;
}
.NET 框架
.NET Framework 兼容版本。它解決了您的原始代碼的問題,即一旦UnauthorizedAccessException拋出例外就中止列舉。此版本繼續使用遞回列舉所有剩余目錄:
internal static async Task<long> GetDirectorySize(string directoryPath)
{
long spaceUsedInBytes = -1;
var drives = DriveInfo.GetDrives();
DriveInfo targetDrive = drives.FirstOrDefault(drive => drive.Name.Equals(directoryPath, StringComparison.OrdinalIgnoreCase));
// Directory is a drive: skip enumeration of complete drive.
if (targetDrive != null)
{
spaceUsedInBytes = targetDrive.TotalSize - targetDrive.TotalFreeSpace;
return spaceUsedInBytes;
}
var targetDirectoryInfo = new DirectoryInfo(directoryPath);
spaceUsedInBytes = await Task.Run(() => SumDirectorySize(targetDirectoryInfo));
return spaceUsedInBytes;
}
private static long SumDirectorySize(DirectoryInfo parentDirectoryInfo)
{
long spaceUsedInBytes = 0;
try
{
spaceUsedInBytes = parentDirectoryInfo.EnumerateFiles("*", SearchOption.TopDirectoryOnly)
.Sum(fileInfo => fileInfo.Length);
}
catch (UnauthorizedAccessException)
{
return 0;
}
foreach (var subdirectoryInfo in parentDirectoryInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly))
{
spaceUsedInBytes = SumDirectorySize(subdirectoryInfo);
}
return spaceUsedInBytes;
}
如何實體化需要在構造上運行異步操作的型別
檔案夾模型.cs
class FolderModel
{
// Make a constructor private to force instantiation using the factory method
private FolderModel(string folderPath)
{
// Do non-async initialization
}
// Async factory method: add constructor parameters to async factory method
public static async Task<FolderModel> CreateAsync(string folderPath)
{
var instance = new FolderModel(folderPath);
await instance.InitializeAsync(folderPath);
return instance;
}
// Define member as protected virtual to allow derived classes to add initialization routines
protected virtual async Task InitializeAsync(string directoryPath)
{
// Consider to throw an exception here ONLY in case the folder is generated programmatically.
// If folder is retrieved from user input, use input validation
// or even better use a folder picker dialog
// to ensure that the provided path is always valid!
if (!Directory.Exists(directoryPath))
{
throw new DirectoryNotFoundException($"Invalid directory path '{directoryPath}'.");
}
long folderSize = await GetDirectorySize(directoryPath);
// TODO::Do something with the 'folderSize' value
// and execute other async code if necessary
}
}
用法
// Create an instance of FolderModel example
private async Task SomeMethod()
{
// Always await async methods (methods that return a Task).
// Call static CreateAsync method instead of the constructor.
FolderModel folderModel = await FolderModel.CreateAsync(@"C:\");
}
在更高級的場景中,當您想推遲初始化,例如因為您想避免分配現在不需要或永遠不需要的昂貴資源時,您可以在參考InitializeAsync依賴于這些資源的某個成員時進行實體呼叫,或者您可以將建構式和InitializeAsync方法公開以允許類的用戶InitializeAsync顯式呼叫。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/372424.html
上一篇:如何遍歷TreeView元素?
