实现IComparer<FileInfo>排序失效,请求排查原因
问题描述
我正在开发一个自定义Folder类,参考了Stack Overflow上关于PowerShell排序DirectoryInfo列表的内容。该类需要实现SortFiles方法,通过自定义Comparer类(实现System.Collections.Generic.IComparer[System.IO.FileInfo]接口)对List[System.IO.FileInfo]集合按文件Length从大到小排序。两类代码编译无错误,但执行SortFiles后,文件列表并未按预期降序排列,求问题原因及解决方法。
自定义Comparer类
class Comparer : System.Collections.Generic.IComparer[System.IO.FileInfo] { [int]Compare([System.IO.FileInfo]$a, [System.IO.FileInfo]$b) { if($a.Length -eq $b.Length) { $res = 0 } elseif($a.Length -lt $b.Length) { $res = -1 } else { $res = 1 } return $res } }
自定义Folder类
class Folder { [System.IO.DirectoryInfo]$Root [System.Collections.Generic.List[System.IO.FileInfo]]$Files [int]$Size Folder([System.String]$Path){ $this.Root = [System.IO.DirectoryInfo]::new($Path) } [void]GetFiles([String[]]$Query){ $this.Files = [System.Collections.Generic.List[System.IO.FileInfo]]::new() ForEach($Q in $Query){ try { $local:Archivos = $this.Root.EnumerateFiles($Q, "AllDirectories") foreach($Archivo in $Archivos){ $File= [System.IO.FileInfo]::new($Archivo.FullName) $this.Files.Add($File) } } catch [System.Management.Automation.MethodInvocationException]{ if($_.FullyQualifiedErrorID -eq "FileNotFoundException"){ [System.Console]::WriteLine($_.Exception.Message) } } } } [void]ListFiles(){ [System.Console]::WriteLine("[Root] $($this.Root.FullName)") foreach($File in $this.Files){ [System.Console]::WriteLine(`t"[$($this.FormatSize($File.Length))] $($File.Name)") } } [void]SortFiles() { $local:Comparer = [Comparer]::new() $this.Files.Sort($local:Comparer) } [void]DeleteFiles(){ foreach($File in $this.Files){ $File.Delete() } } [void]GetSize(){ [System.Int64]$this.Size = 0 foreach($File in $this.Files){ $this.Size += $File.Length } } [System.String]FormatSize([System.Int64]$Size){ $local:Formatato = "" switch ($Size) { {$Size -lt 1099511627776}{ $Formatato = "$([System.Math]::Round(($Size/1GB), 2))GB" } {$Size -lt 1073741824}{ $Formatato = "$([System.Math]::Round(($Size/1MB), 2))MB" } {$Size -lt 1048576}{ $Formatato = "$([System.Math]::Round(($Size/1KB), 2))KB" } Default { $Formatato = "$([System.Math]::Round(($Size), 2))B" } } return $local:Formatato } }
类测试结果
$Downloads = [Folder]::new($Path) $Downloads.GetFiles("*") $Downloads.SortFiles() $Downloads.ListFiles() [Root] C:\Users\charles.murray\Downloads [0.6KB] index.html.example [0.91KB] prometheus.yml [1.3KB] prometheus.html [1.42KB] node.html [2.61KB] node-cpu.html [2.82KB] menu.lib [3.44KB] node-disk.html [3.68KB] NOTICE [4.01KB] prometheus-overview.html [6.01KB] prom.lib [19.53KB] queries.active [73.48KB] rufus.log [896KB] 00000000 [8.72MB] MS108EUP_V1.0.1.9-runtime.image [108.23MB] promtool.exe [114.81MB] prometheus.exe [128MB] 000001 $Downloads.Files Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 7/17/2023 2:01 PM 616 index.html.example -a---- 7/17/2023 2:00 PM 934 prometheus.yml -a---- 8/4/2023 11:31 PM 1114 MS108EUP_V1.0.1.9_Release_Notes.html -a---- 7/17/2023 2:01 PM 1334 prometheus.html -a---- 7/17/2023 2:01 PM 1453 node.html -a---- 7/17/2023 2:01 PM 2675 node-cpu.html -a---- 7/17/2023 2:01 PM 2888 menu.lib -a---- 7/17/2023 2:01 PM 3522 node-disk.html -a---- 7/17/2023 2:00 PM 3773 NOTICE -a---- 7/17/2023 2:01 PM 4103 prometheus-overview.html -a---- 7/17/2023 2:01 PM 5783 node-overview.html -a---- 7/17/2023 2:01 PM 6152 prom.lib -a---- 7/17/2023 2:00 PM 11357 LICENSE -a---- 7/17/2023 2:01 PM 20001 queries.active -a---- 7/26/2023 11:57 AM 75243 rufus.log -a---- 7/17/2023 3:11 PM 917504 00000000 -a---- 8/4/2023 11:31 PM 9143718 MS108EUP_V1.0.1.9-runtime.image -a---- 7/17/2023 2:01 PM 113488896 promtool.exe -a---- 7/17/2023 2:00 PM 120385536 prometheus.exe -a---- 7/17/2023 3:11 PM 134217728 000001
问题原因及解决方法
原因
当前Comparer类的Compare方法逻辑是升序排序:
- 当
$a.Length -lt $b.Length时返回-1,表示$a应该排在$b前面 - 当
$a.Length -gt $b.Length时返回1,表示$a应该排在$b后面
这会让List.Sort()方法按文件从小到大排列,和需求的**降序(从大到小)**相反。
解决方法
修改Comparer类的Compare方法,反转返回值即可实现降序:
修改后的Comparer类
class Comparer : System.Collections.Generic.IComparer[System.IO.FileInfo] { [int]Compare([System.IO.FileInfo]$a, [System.IO.FileInfo]$b) { if($a.Length -eq $b.Length) { return 0 } elseif($a.Length -lt $b.Length) { return 1 # 反转:小的文件排在后面 } else { return -1 # 反转:大的文件排在前面 } } }
或者更简洁的写法,直接调用long类型的CompareTo方法并反转结果:
class Comparer : System.Collections.Generic.IComparer[System.IO.FileInfo] { [int]Compare([System.IO.FileInfo]$a, [System.IO.FileInfo]$b) { # 用b的长度和a比较,直接得到降序结果 return $b.Length.CompareTo($a.Length) } }
修改后重新执行SortFiles方法,文件列表就会按Length从大到小排列。
内容的提问来源于stack exchange,提问作者user23078090
相关产品推荐
相关产品推荐

