【问题标题】:Best Way to Sort GetFiles对 GetFiles 进行排序的最佳方法
【发布时间】:2015-05-01 15:01:01
【问题描述】:

我正在尝试按此顺序对以下文件进行排序:

TMP_SDF_1180741.PDF
TMP_SDF_1179715.PDF
TMP_SDF_1162371.PDF
TMP_SDF_1141511.PDF
TMP_SDF_1131750.PDF
TMP_SDF_1117362.PDF
TMP_SDF_1104199.PDF
TMP_SDF_1082698.PDF
TMP_SDF_1062921.PDF
TMP_SDF_1043875.PDF
TMP_SDF_991514.PDF
TMP_SDF_970621.PDF
TMP_SDF_963154.PDF
TMP_SDF_952954.PDF
TMP_SDF_948067.PDF
TMP_SDF_917669.PDF
TMP_SDF_904315.PDF
TMP_SDF_899902.PDF
TMP_SDF_892398.PDF
TMP_SDF_882024.PDF

但实际输出是这样的:

TMP_SDF_991514.PDF
TMP_SDF_970621.PDF
TMP_SDF_963154.PDF
TMP_SDF_952954.PDF
TMP_SDF_948067.PDF
TMP_SDF_917669.PDF
TMP_SDF_904315.PDF
TMP_SDF_899902.PDF
TMP_SDF_892398.PDF
TMP_SDF_882024.PDF
TMP_SDF_1180741.PDF
TMP_SDF_1179715.PDF
TMP_SDF_1162371.PDF
TMP_SDF_1141511.PDF
TMP_SDF_1131750.PDF
TMP_SDF_1117362.PDF
TMP_SDF_1104199.PDF
TMP_SDF_1082698.PDF
TMP_SDF_1062921.PDF
TMP_SDF_1043875.PDF

我曾尝试通过 GetFiles 研究排序方法,但是当我应用它们时,我收到有关系统集合无法绑定到一维数组的错误,这令人沮丧。这是我的代码:

Dim di As New IO.DirectoryInfo("C:\temp")
        Dim aryFi As IO.FileInfo() = di.GetFiles("*.PDF")
        Dim fi As IO.FileInfo       
        For Each fi In aryFi
            My.Computer.FileSystem.RenameFile("C:\TEMP\" & fi.Name, listBox1.SelectedItem.ToString & ".pdf")
            listBox1.SelectedIndex = listBox1.SelectedIndex - 1
        Next

我将文件重命名为 a1 a2 a3 等,这样当我在 PDF 中组合时,它们是按时间顺序排列的。我想要排序的方式,将它们按时间顺序排列。我相信有一个更简单的方法。如您所知,PDF 文件 (1180741) 中的数字越大,文件内容的最近日期就越多。而 882024 将是最旧的文件内容。

【问题讨论】:

  • 它正在进行 alpha 排序。 数字代表一个日期或序列对你无关紧要,它只是给计算机的文本,这样“9”将排序高于“10734756”。跨度>
  • 我不是 100% 清楚你想要做什么。如果要按字母顺序获取文件名列表,请将文件名放入字符串类型的数组列表中,然后使用排序方法。如果要反方向排序,在排序方法后使用reverse方法。
  • 为了扩展 Plutonix 的评论,Explorer 将对数字进行不同的排序,因为它假定您希望将它们视为数字,而不是文本。
  • 有许多不同的方法可以实现这一点。也许最容易解释的是,如果文件名的非数字部分始终相同,则去掉字母,将它们放入整数数组中,对它们进行排序,然后在输出中将字母加回。

标签: vb.net sorting


【解决方案1】:

正如 cmets 中所述,您需要按数字而非字母顺序对它们进行排序。我不知道 Windows 资源管理器使用的特定排序算法,或者是否可以使用相同的库,但当然可以编写自己的算法来进行排序。

这样做的第一步是仅提取要用作排序键的数字部分。在不了解更多细节的情况下,很难说最好的选择是什么。如果您知道数字总是从字符串中的特定字符位置开始,您可以简单地使用String.SubString。如果它总是由“_”和“.”分隔你可以使用String.Split。如果您需要更复杂的东西,或者如果您需要可配置的解析规则,您可能需要考虑使用 RegEx。例如,这里有一个使用String.Split的简单示例方法:

Public Function GetSortKey(fileName As String) As Integer
    Return Integer.Parse(fileName.Split({"_"c, "."c})(2))
End Function

一旦你有一种方法可以为给定的文件名提取排序键,你就可以使用它来对它们进行排序,如下所示:

di.GetFiles("*.PDF").OrderBy(Function(x) GetSortKey(x.Name))

【讨论】:

  • 我觉得这会奏效。感谢您的辛勤工作。但我有以下错误: 无法在此行上转换为一维数组: Dim aryFi As IO.FileInfo() = di.GetFiles("*.PDF").OrderBy(Function(x) GetSortKey(x. Name)) -- 请注意,我在这之后使用了一个 for 循环来重命名数组中的每个文件。
  • OrderBy LINQ 扩展方法不返回数组。它返回一个IEnumerable(Of T)(在本例中为IEnumerable(Of FileInfo))。因此,要么将aryFi 更改为IEnumerable(Of FileInfo),要么使用LINQ 的ToArray 函数(例如...OrderBy(...).ToArray())将返回值转换为数组。
  • 添加 .ToArray 缓解了该错误,但现在我为解析方法输入了错误的字符串。实际文件名如下所示: TMP38667016-R_prod_1180741-095621.PDF - 所以我将解析方法更改为: (fileName.Split({"_"c, "-"c})(2)) - 但也许我不明白解析在做什么。我试图从逻辑上分析并看到它在 _ 的第二个实例中分裂,也许我错了。我只需要对1180741的整数值进行排序我不关心095621
  • 在该示例文件名 (TMP38667016-R_prod_1180741-095621.PDF) 中,您想将哪个部分用作排序键?
  • 1180741 应该是排序键。所以 _ 和 - 之间的任何东西
【解决方案2】:

也许您可以利用手头的一些工具

    Dim reg As RegEx = new RegEx("\d+")
    Dim ordered = new List(Of OrderedFiles)()
    for each s in Directory.GetFiles("C:\temp", "*.PDF")
        Dim aFile = new OrderedFiles() 
        aFile.FileName = s
        aFile.Sequence = Convert.ToInt32(reg.Match(s).Value)
        ordered.Add(aFile)
    Next

    for each aFile in ordered.OrderByDescending(Function(x) x.Sequence)
        Console.WriteLine(Path.GetFileName(aFile.FileName))
    Next
End Sub


Class OrderedFiles
    Public FileName as String
    Public Sequence as Integer
End Class

在此示例中,您有一个自定义类,其中包含要排序的文件名和数字部分。然后,将匹配文件中任何数值的 Regex 表达式应用于您的文件,以构建具有名称和数字部分的类的实例。在循环结束时,只需调用 Linq 方法,按降序排列您的列表

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-07
    • 2017-05-23
    • 2021-01-04
    • 2011-01-24
    • 2013-12-19
    • 2014-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多