Vb.net 已排序目录列表中的已排序文件列表

Vb.net 已排序目录列表中的已排序文件列表,vb.net,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 。。。其中myPat

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

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格式的日期命名的目录

如何从中获得排序目录列表和排序文件列表? 例如,如果我需要2014年5月12日的文件。至2014年5月15日。应列出文件0004.xml、0006.xml、0008.xml、0009.xml。请注意,缺少一些文件,也缺少一些日期。 目录应按字母顺序读取


如何做到这一点?

简单明了:

    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
您的日期已经是yyyyMMdd格式,基本上是整数:易于排序->使用SortedListOf Int32,任何内容 我假设您的文件系统结构是不可变的:您总是有一个日期文件夹名称的有序列表,每个日期都有一个文件名列表。 免责声明:太长,无法在IDE中测试。。可能包含打字错误或不起作用的东西,我将在以后的某个时候尝试修复 快点。。 尤其是当我不确定是否允许我安全地访问.key时 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(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
这是一个过载:

    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
下面是基本功能:

    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
公共声明与目录的声明几乎相同,但调用GetFileRangeDateStart、DateEnd

然后你可以写:

Try
    Dim MyListOfDir As List(Of String) = _
        New CustomDateTypeDirectory(myPath)().GetDirectoryRange( _
            DateStart, DateEnd, True, False)
    ' ....
' ....
您可以将Try替换为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
对GetFileRangeDateStart、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 782年11月25日


提示:虽然这可能不是最优雅的方式,但它很容易实现。您可以将文件信息读入ADO.NET数据表。在填充DataTable时,可以使用父级的日期填充缺少的日期。使用ADO排序、筛选功能获取所需内容。有些代码已经在这里了:。

好的。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

我之所以不喜欢Linq,是因为调试代码的难度比这复杂得多

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

yyyyMMdd\*.*
yyyyMMdd_Saturday\*.*
yyyyMMdd_Monday_ToDo_Series\*.*
并且可以包含以下子目录:

\_Installed
\_Rejected
\_Revised

对于性能问题,Int32是我的最佳选择,每个用户操作数千次查询,以及绘制GDI+或解压缩zip文件等其他令人眼花缭乱的事情,但是Karl,您的场景非常复杂。请注意,我的目录和文件名已经可以作为字符串进行排序。这里应该有更简单的解决方案。无论如何,感谢您提供值得研究的示例。堆栈溢出不是一种代码编写服务。如果您向我们展示您尝试过的代码并解释为什么它不起作用,我们可以帮助您。谁说堆栈溢出是代码编写服务?我的代码可能会将可能的解决方案转向错误的方向,所以有时候最好从独立的角度来看待常见的问题,比如我的问题。看来你在投反对票之前想得不够。嗯,也很复杂。您是否建议我使用DirectoryInfo.GetFiles来排列dirInfo+fileinfo,并使用相关的IComparer对其进行排序。不是很快,但我想编码更少?无论如何,你的例子很有教育意义,所以我会接受你的答案。谢谢。@user973238-如果1和2的类型相同,则可以使用Anything1+Anything2的数组。DirInfo和FileInfo的类型不同。您可以使用字符串路径,但您完成了一项特定任务:选择一组提供开始日期和结束日期的目录和/或文件。排序非常简单,而且你的数组会做得很好;然后,考虑代码以获取范围内的文件。。您将得到与上面的Linq示例一样多的行:@user973238-关键部分不是对集合进行排序。每个排序通常是InRangeDir与Linq的一行代码顺序;字符串的排序。。。;数组.排序。。关键部分是选择范围内的项目。该任务使代码变长。。。如果按子目录yyyyMMdd\xxxx.xml排序,将失去提取yyyyMMdd的能力,因此必须编写更多代码来提取该文件。这就是为什么最好将目录解析与使用键的直接项访问(例如在变量或类中)结合起来。另一个答案这个答案只是绕过所有的tha
t、 @user973238-谢谢你的投票和接受:复杂是品味的问题。如果有这样的东西就太好了:Dim Files As String=Array.JoinDirectory.selectinginmypath Where DateStart*我不知道。这里涉及ADO似乎“有点过于复杂”。
yyyyMMdd\*.*
yyyyMMdd_Saturday\*.*
yyyyMMdd_Monday_ToDo_Series\*.*
\_Installed
\_Rejected
\_Revised