如何按文件名编号列出文件列表?

时间:2015-11-18 16:22:16

标签: vb.net linq sorting

我在一个目录中有一堆文件,我试图根据它们的类型获取。一旦我拥有它们,我想按文件名命令它们(其中有一个数字,我想以这种方式订购)

我的文件返回:

file-1.txt
file-2.txt
...
file-10.txt
file-11.txt
...
file-20.txt

但我得到它们的顺序看起来更接近于此:

file-1.txt
file-10.txt
file-11.txt
...
file-2.txt
file-20.txt

现在我正在使用Directory.GetFiles()并尝试使用linq OrderBy属性。但是,我很难完成我需要做的事情来订购我的文件列表,如上面的第一个列表。

Directory.GetFiles()似乎返回了一个字符串列表,因此我无法获取filenamename等文件属性列表。

这是我目前的代码:

documentPages = Directory.GetFiles(documentPath, "*.txt").OrderBy(Function(p) p).ToList()

有人会有任何想法吗?

2 个答案:

答案 0 :(得分:4)

听起来你可能正在寻找一个" NaturalSort" - 文件资源管理器用于命令包含数字的文件名的显示类型。为此,您需要一个自定义比较器:

Imports System.Runtime.InteropServices

Partial Class NativeMethods
    <DllImport("shlwapi.dll", CharSet:=CharSet.Unicode)>
    Private Shared Function StrCmpLogicalW(s1 As String, s2 As String) As Int32
    End Function

    Friend Shared Function NaturalStringCompare(str1 As String, str2 As String) As Int32
        Return StrCmpLogicalW(str1, str2)
    End Function
End Class

Public Class NaturalStringComparer
    Implements IComparer(Of String)

    Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
        Return NativeMethods.NaturalStringCompare(x, y)
    End Function
End Class

用它来对你得到的结果进行排序:

Dim myComparer As New NaturalStringComparer

' OP post only shows the filename without path, so strip off path:
' (wont affect the result, just the display)
Dim files = Directory.EnumerateFiles(path_name_here).
                 Select(Function(s) Path.GetFileName(s)).ToList
Console.WriteLine("Before: {0}", String.Join(", ", files))

' sort the list using the Natural Comparer:
files.Sort(myComparer)
Console.WriteLine("After: {0}", String.Join(", ", files))

结果(单行以节省空间):

  

之前:file-1.txt,file-10.txt,file-11.txt,file-19.txt,file-2.txt,file-20.txt,file-3.txt,file-9 .txt,file-99.txt
  之后:file-1.txt,file-2.txt,file-3.txt,file-9.txt,file-10.txt,file-11.txt,file-19.txt,file-20.txt,文件-99.txt

这样做的一个优点是它不依赖于特定的模式或编码。它更通用,将在文本中处理多组数字:

  
    

权力的游戏\ 4 - 乌鸦的盛宴\ 1 - Prologue.mp3
    权力的游戏\ 4 - 乌鸦的盛宴\ 2 - The Prophet.mp3
    ...
    权力的游戏\ 4 - 乌鸦的盛宴\ 10 - Brienne II.mp3
    权力的游戏\ 4 - 乌鸦的盛宴\ 11 - Sansa.mp3

  

Natural String Sort非常方便,我个人不介意通过创建扩展来污染Intellisense:

' List<string> version
<Extension>
Function ToNaturalSort(l As List(Of String)) As List(Of String)
    l.Sort(New NaturalStringComparer())
    Return l
End Function

' array version
<Extension>
Function ToNaturalSort(a As String()) As String()
    Array.Sort(a, New NaturalStringComparer())
    Return a
End Function

现在使用起来更加容易:

Dim files = Directory.EnumerateFiles(your_path).
              Select(Function(s) Path.GetFileName(s)).
              ToList.
              ToNaturalSort()

' or without the path stripping:
Dim files = Directory.EnumerateFiles(your_path).ToList.ToNaturalSort()

答案 1 :(得分:2)

我假设file.txt部分是可变的,并且在这里作为文件名和类型的占位符可以变化。

我不经常使用正则表达式,所以这可能还需要一些工作,但它绝对是您需要的方向:

Dim exp As String = "-([0-9]+)[.][^.]*$"
documentPages = Directory.GetFiles(documentPath, "*.txt").OrderBy(Function(p) Integer.Parse(Regex.Matches(p, exp)(0).Groups(1).Value)).ToList()

再看一遍,我发现我错过了你正在过滤*.txt个文件,这可以帮助我们缩小表达范围:

Dim exp As String = "-([0-9]+)[.]txt$"

另一个包含测试数据的答案带来的另一个可能的改进是允许-和数字之间的空格:

Dim exp As String = "-[ ]*([0-9]+)[.]txt$"

如果文本文件不遵循该模式,则进一步值得注意的是上述失败。如果需要,我们可以说明这一点:

Dim exp As String = "-[ ]*([0-9]+)[.][^.]*$"
Dim docs = Directory.GetFiles(documentPath, "*.txt")
documentPages = docs.OrderBy(
     Function(p) 
            Dim matches As MatchCollection = Regex.Matches(p, exp)
            If matches.Count = 0 OrElse matches(0).Groups.Count < 2 Then Return 0
            Return Integer.Parse(matches(0).Groups(1).Value)
     End Function).ToList()

您也可以使用Integer.MaxValue作为默认选项,具体取决于您是希望这些选项出现在列表的开头还是结尾。