从已排序的目录列表中排序的文件列表

时间:2014-11-25 07:16:13

标签: vb.net

我有这样的目录/文件结构:

myPath\20140511\0002.xml
               \0003.xml
      \20140513\0004.xml
               \0006.xml
               \0008.xml
      \20140515\0009.xml
      \20140516\0010.xml
               \0011.xml
               \0012.xml

...其中myPath是数据的基本目录,然后是" yyyyMMdd"中日期命名的目录。格式。

我如何获得带有排序文件列表的排序目录列表​​?
例如,如果我需要12.05.2014的文件。到2014年5月15日。应列出文件0004.xml,0006.xml,0008.xml,0009.xml。请注意,缺少一些文件,也缺少一些日期 目录应按字母顺序阅读。

如何获得?

3 个答案:

答案 0 :(得分:1)

简单明了:

  • 您的日期已经采用yyyyMMdd格式,基本上是整数:易于排序 - >使用SortedList(Of Int32, Anything
  • 我假设您的FileSystem结构是不可变的:您将始终拥有日期(文件夹名称)的有序列表,并且每个 date 都有一个File列表(名)第

  

免责声明:在IDE中测试它的时间太长了...可能包含错别字或者不能处理以后我会尝试修复的东西(有点像   快点..)   特别是当我不确定是否允许我安全地访问 .Keys 时   SortedList的属性(记住一个例外,例如“IList改变了   访问集合......“)


我会创建一个类(虽然你也可以不用)

Imports System.IO

Private Class CustomDateTypeDirectory
    Private p_BaseDirectory As String = ""
    Private p_FileSystem As SortedList(Of Int32, List(Of String)) = Nothing

    Public Sub New(ByVal NewDirectoryPath As String)
        ' where NewDirectory stands for myPath
        If Directory.Exists(NewDirectoryPath) Then
            p_FileSystem = New SortedList(Of Int32, List(Of String))
            ParseDirectory(NewDirectoryPath) ' -> below...
        Else
            ' ... Throw New Exception()
        End If
    End Sub

    ' Called by New() -> Parse your myPath Directory SubFolders
    Private Sub ParseDirectory(ByVal NewDirectoryPath As String)
        Dim AllDirectories As String() = Directory.GetDirectories(NewDirecoryPath)
        Dim SubDirName As Int32 = -1

        p_FileSystem.Clear()
        For Each SubDir As String In AllDirectories
            SubDirName = IsDateFolder(Path.GetDirectoryName(SubDir))
            If SubDirName > -1 Then
                p_FileSystem.Add(SubDirName, GetFilesOf(SubDir))
            End If
        Next
    End Sub

    ' Called by ParseDirectory() -> Validate a SubDir Name as expression of Date
    Private Function IsDateFolder(ByVal DirName As String) As Int32
        ' Here you'll define how you'll consider the name as a valid "yyyyMMdd"
        If DirName.Length = 8 Then
            Dim IntValidator As Int32 = -1
            If Integer.TryParse(DirName, IntValidator) Then
                ' You could do more checks like if IntValidator > 20000101...
                ' Or simply try parsing the represented Date...
                ' I sometimes use "20140300" dit names when I don't know the day,
                ' so while using Date would throw an exception, 
                ' my function just simply don't care using Integers...
                Return IntValidator
            Else
                Return -1
            End If
        Else
            Return -1
        End If
    End Function

    ' Called by ParseDirectory() -> Gather Files of Date SubFolder
    Private Function GetFilesOf(ByVal DirPath As String) As List(Of String)
        ' I'm assuming you make sure to properly sort the Files
        Dim AllFiles As String() = Directory.GetFiles(DirPath)
        Dim FilesList As New List(Of String)

        For Each CurrentFile As String In AllFiles
            ' Use condition validation if your subDir can contain other files..
            FilesList.Add(Path.GetFileName(CurrentFile))
        Next

        Return FilesList
    End Function

End Class

然后创建一些函数以使用您的类

这是基本声明:

    Private Function GetDirectoryRange( _
        ByVal DateStart As Int32, _
        ByVal DateEnd As Int32) As List(Of String)
        ' ...
    End Function

这是一个过载:

    Public Function GetDirectoryRange( _
        ByVal DateStart As Int32, _
        ByVal DateEnd As Int32, _
        ByVal IncludeStartingDate As Boolean, _
        ByVal IncludeEndingDate As Boolean) As List(Of String)
        ' ...
    End Function

请注意,基本声明为私有,而其他声明为公开

需要另外两个私人功能:

    Private Function GetNearestStartingDate(ByVal DateStart As Int32) As Int32
        If p_FileSystem.Count > 0 Then
            If p_FileSystem.ContainKey(DateStart) Then
                Return DateStart
            Else
                ' Find next available Date...
                If p_FileSystem.Keys.Item(0) > DateStart Then
                    Return p_FileSystem.Keys.Item(0)
                ElseIf p_FileSystem.Keys.Item(p_FileSystem.Keys.Count - 1) < DateStart Then
                    Return - 1 ' DateStart greater than last folder..
                Else
                    ' Okay -_- ! Let's find an existing starting Date...
                    ' Simpliest way is iterating the integers 
                    ' until it's greater than DateStart
                    Dim i As Int32 = 1 ' we've already checked for i = 0
                    While DateStart > p_FileSystem.Keys.Item(i)
                        i += 1
                    End While

                    Return p_FileSystem.Keys.Item(i)
                End If
            End If
        Else
            Return -1 ' No StartingDate
        End If
    End Function

我假设您能够创建另一个GetNearestEndingDate()函数..(查看您的声誉得分)


不知道为什么上面的基本声明是私有的?因为它仅在中使用有效的DateStart和DateEnd输入

这是公开声明:

    Public Function GetDirectoryRange(DateStart, DateEnd, IncludeStartingDate, IncludeEndingDate) As List(Of String)

        ' First, fix some possible issues :
        If DateStart > DateEnd Then
            Dim TempDate As Int32 = DateStart
            DateStart = DateEnd
            DateEnd = TempDate
        End If ' obvious

        If Not IncludeStartingDate Then DateStart = DateStart + 1
        If Not IncludeEndingDate Then DateEnd = DateEnd - 1

        ' Now let's find actual values of DateStart and DateEnd...
        If DateStart <= DateEnd Then ' Okay, let's look for available dates...
            DateStart = GetNearestStartingDate(DateStart)
            If DateStart > -1 Then
                DateEnd = GetNearestEndingDate(DateEnd)
                If DateEnd >= DateStart Then
                    Return GetDirectoryRange(DateStart, DateEnd)
                Else
                    Return Nothing ' Or Return New List(Of String) - empty !
                End If
            Else
                Return Nothing
            End If
        Else
            Return Nothing
        End If
    End Function

然后这是基本功能:

    Private Function GetDirectoryRange(DateStart, DateEnd) As List(Of String)
        Dim NewList As New List(Of String)
        Dim DateIndex As Int32 = p_FileSystem.IndexOfKey(DateStart) + 1

        NewList.Add(p_BaseDirectory + "\" + DateStart.ToString())
        While p_FileSystem.Keys.Item(DateIndex) <= DateEnd
            NewList.Add( _
                p_BaseDirectory + "\" _
                + p_FileSystem.Keys.Item(DateIndex).ToString())
            DateIndex = DateIndex + 1
        End while

        Return NewList ' New List should contain at least one entry.
    End Function

获取文件的函数外推非常简单:

    Private Function GetFilesRange(DateStart, DateEnd) As List(Of String)
        Dim NewList As New List(Of String)
        Dim DateIndex As Int32 = p_FileSystem.IndexOfKey(DateStart)
        Dim CurrentFilesList As List(Of String)

        Do
            CurrentFilesList = p_FileSystem.Item(p_FileSystem.Keys.Item(DateIndex))
            For Each CurrentFile As String In CurrentFilesList
                NewList.Add( _
                    p_BaseDirectory + "\" _
                    + p_FileSystem.Keys.Item(DateIndex).ToString() + "\" _
                    + CurrentFile)
                ' As CurrentFile if FileName without root path.
            Next
            DateIndex = DateIndex + 1
        Until p_FileSystem.Keys.Item(DateIndex) > DateEnd

        Return NewList ' New List should contain at least one entry.
    End Function

公开声明与目录声明几乎相同,但改为调用GetFilesRange(DateStart,DateEnd)。


然后你可以写:

Try
    Dim MyListOfDir As List(Of String) = _
        New CustomDateTypeDirectory(myPath)().GetDirectoryRange( _
            DateStart, DateEnd, True, False)
    ' ....
' ....

你可以用

替换Try with If块
    Dim MyDir As New CustomDateTypeDirectory(myPath)
    Dim MyListOfDir As List(Of String) = _
        MyDir.GetDirectoryRange(DateStart, DateEnd, True, False)
    If MyListOfDir IsNot Nothing Then
    ' or If MyListOfDir.Count > 0 ... depending on how the Function returns value
        ' ...
    End If

GetFilesRange(DateStart, DateEnd, True, False) ....

执行相同的操作

您还可以使用新参数类型重载公共声明:

    Public Function GetFilesRange( _
        ByVal DateStart As Date, ByVal DateEnd As Date, Bool1, Bool2) _
        As List(Of String)

        ' Convert Dates to Int32
        Dim IntDateStart As Int32 = _
            DateStart.Year * 1000 _
            + DateStart.Month * 100 _
            + DateStart.Day

        ' ...
        Return GetFilesRange(IntDateStart, IntDateEnd, Bool1, Bool2)
    End Function

    Public Function GetFilesRange( _
        ByVal DateStart As String, ByVal DateEnd As String, Bool1, Bool2) _
        As List(Of String)

        ' Convert Dates to Int32
        Dim IntDateStart As Int32 = IsDateFolder(DateStart)
        Dim IntDateEnd As Int32 = IsDateFolder(DateEnd)

        If (IntDateStart > -1) AndAlso (IntDateEnd > -1) Then
            Return GetFilesRange(IntDateStart, IntDateEnd, Bool1, Bool2)
        Else
            Return Nothing ' Or Return New List(Of String)()
        End If
    End Function

  

当然,上面的所有内容都不适用于日期文件夹   例如,以低于1000年的任何日期命名。即如果你   你的文件夹中有前导零“0”,如“07821125”所示   11月25日,782 ......

答案 1 :(得分:1)

提示:虽然这可能不是最优雅的方式,但实施起来很容易。您可以将文件信息读入ADO.NET DataTable。在填写DataTable时,您可以使用父日期填写缺少的日期。使用ADO排序,过滤功能来获得您想要的。部分代码已在此处:filling-a-grid-with-files-in-a-folder

答案 2 :(得分:1)

好。 Linq - 爱好者会对这个非常基本的代码感到满意:)

Imports System.Linq
Imports System.IO

核心功能:

Private Function GetSubDirs( _
    ByVal myPath As String, _
    ByVal DateStart As String, ByVal DateEnd As String) _
    As IEnumerable(Of String)

    DateStart = myPath + "\" + DateStart
    DateEnd = myPath + "\" + DateEnd
    ' weird isn't it ? but heh ! it works...

    Dim SelectedSubDirs As IEnumerable(Of String) = _
        From InRangeDir In Directory.GetDirectories(myPath) Order By InRangeDir
        Where (InRangeDir >= DateStart) AndAlso (InRangeDir <= DateEnd)

    Return SelectedSubDirs
End Function

Private Function GetSubDirFiles(ByVal CurrentDir As String) _
    As IEnumerable(Of String)
    ' Gets the Files of one Sub Dir sorted in ascending order.
    Return From AnyFile In Directory.GetFiles(CurrentDir) Order By AnyFile
End Function

然后你需要打电话:

Public Function GetSubDirsFilesRange( _
    ByVal myPath As String, _
    ByVal DateStart As String, ByVal DateEnd As String) _
    As List(Of String)
    ' Gets all the Files in a range of Directory Dates.

    Dim AllFiles As New List(Of String)()
    Dim SelectedSubDirs As IEnumerable(Of String) = _
        GetSubDirs(myPath, DateStart, DateEnd)

    For Each CurrentDir As String In SelectedSubDirs
        AllFiles.AddRange(GetSubDirFiles(CurrentDir))
    Next

    Return AllFiles
End Function

Public Function GetSubDirsRange( _
    ByVal myPath As String, _
    ByVal DateStart As String, ByVal DateEnd As String) _
    As List(Of String)

    Return GetSubDirs(myPath, DateStart, DateEnd).ToList()
End Function

GetSubDirsFilesRange(myPath, "20140512", "20140515")
    ' myPath\20140513\0004.xml
    ' myPath\20140513\0006.xml
    ' myPath\20140513\0008.xml
    ' myPath\20140515\0009.xml

为什么我不喜欢Linq调试比这更复杂的代码的难度。

另一个答案来自我的AddonManager,它处理数千个zip文件和目录作为游戏的资源。我的文件夹方案是类型:

yyyyMMdd\*.*
yyyyMMdd_Saturday\*.*
yyyyMMdd_Monday_ToDo_Series\*.*

并且可以包含以下子目录:

\_Installed
\_Rejected
\_Revised

Int32是性能问题的最佳选择(每个用户操作数千个查询,以及绘制GDI +或(un)打包zip文件等其他令人眼花缭乱的东西)