You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 05:47:04