Sorting Directory.GetFiles()
Asked Answered
D

13

69

System.IO.Directory.GetFiles() returns a string[]. What is the default sort order for the returned values? I'm assuming by name, but if so how much does the current culture effect it? Can you change it to something like creation date?

Update: MSDN points out that the sort order is not guaranteed for .Net 3.5, but the 2.0 version of the page doesn't say anything at all and neither page will help you sort by things like creation or modification time. That information is lost once you have the array (it contains only strings). I could build a comparer that would check for each file it gets, but that means accessing the file system repeatedly when presumably the .GetFiles() method already does this. Seems very inefficient.

Doretheadoretta answered 9/9, 2008 at 20:33 Comment(1)
Here's the MSDN link: msdn.microsoft.com/en-us/library/07wt70x2.aspx "The order of the returned file names is not guaranteed; use the Sort method if a specific sort order is required."Gilmagilman
G
114

If you're interested in properties of the files such as CreationTime, then it would make more sense to use System.IO.DirectoryInfo.GetFileSystemInfos(). You can then sort these using one of the extension methods in System.Linq, e.g.:

DirectoryInfo di = new DirectoryInfo("C:\\");
FileSystemInfo[] files = di.GetFileSystemInfos();
var orderedFiles = files.OrderBy(f => f.CreationTime);

Edit - sorry, I didn't notice the .NET2.0 tag so ignore the LINQ sorting. The suggestion to use System.IO.DirectoryInfo.GetFileSystemInfos() still holds though.

Genova answered 9/9, 2008 at 20:47 Comment(10)
No LINQ in .Net2.0, but the still the best answer so far.Doretheadoretta
I had to unaccept the answer, because when I went back today to implement it the .Net 2.0 method is called .GetFileSystemEntries, and it still only returns a string array.Doretheadoretta
Joel, you're looking on the wrong object. System.IO.Directory has the GetFileSystemEntries method. My suggestion was to instead use System.IO.DirectoryInfo, which has the GetFileSystemInfos method. Hope this helps.Genova
Technically, you can do LINQ-to-Objects in .NET 2, which is all you'd need for this sort of sorting. albahari.com/nutshell/linqbridge.aspxPinkston
For the LINQ-happy, you can do this in one call: new DirectoryInfo(directory).GetFileSystemInfos().OrderBy(f => f.CreationTime). Awesome!Gascon
@Gascon - the LINQ-happy or the dense/terse-code happy? I personally do quite like chaining operators in the way you suggest, but it can make things harder to read / debug.Genova
@IanNelson I like terse, readable code. Once you understand LINQ, it's easy to make sense (albeit you can't debug it).Gascon
di.GetFileSystemInfos() will get you subdirectories too, if you want just files, use di.GetFiles() which returns FileInfo[] that also has CreationTime property.Early
Why use GetFileSystemInfos? The DirectoryInfo was not enough?Teutonize
@S.Serp It's not enough if you want details of files within the directory. None of the properties on the DirectoryInfo class provide details of the files, you have to invoke one of its methods such as GetFileSystemInfos or the newer EnumerateFileSystemInfos, which wasn't available in .NET 2.0Genova
R
13

In .NET 2.0, you'll need to use Array.Sort to sort the FileSystemInfos.

Additionally, you can use a Comparer delegate to avoid having to declare a class just for the comparison:

DirectoryInfo dir = new DirectoryInfo(path);
FileSystemInfo[] files = dir.GetFileSystemInfos();

// sort them by creation time
Array.Sort<FileSystemInfo>(files, delegate(FileSystemInfo a, FileSystemInfo b)
                                    {
                                        return a.LastWriteTime.CompareTo(b.LastWriteTime);
                                    });
Robertson answered 10/11, 2008 at 20:57 Comment(1)
Hey Chris, is the comment in the code incorrect? You state sort by creation time, but LastWriteTime is used not CreationTime? Just realised how after the face this comment is!Dichogamy
D
12

Here's the VB.Net solution that I've used.

First make a class to compare dates:

Private Class DateComparer
    Implements System.Collections.IComparer

    Public Function Compare(ByVal info1 As Object, ByVal info2 As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim FileInfo1 As System.IO.FileInfo = DirectCast(info1, System.IO.FileInfo)
        Dim FileInfo2 As System.IO.FileInfo = DirectCast(info2, System.IO.FileInfo)

        Dim Date1 As DateTime = FileInfo1.CreationTime
        Dim Date2 As DateTime = FileInfo2.CreationTime

        If Date1 > Date2 Then Return 1
        If Date1 < Date2 Then Return -1
        Return 0
    End Function
End Class

Then use the comparer while sorting the array:

Dim DirectoryInfo As New System.IO.DirectoryInfo("C:\")
Dim Files() As System.IO.FileInfo = DirectoryInfo.GetFiles()
Dim comparer As IComparer = New DateComparer()
Array.Sort(Files, comparer)
Dacey answered 29/9, 2008 at 15:12 Comment(1)
I've edited the sample code because Array.Sort needs an instance of the DateComparer, or we get a "DateComparer is a type and can't be used as an expression" error. Thank you for the code as it was almost ready to use.Hexameter
S
9

Dim Files() As String
Files = System.IO.Directory.GetFiles("C:\")
Array.Sort(Files)
Splasher answered 9/9, 2008 at 20:35 Comment(1)
This is sorting by filename right?..would have been nice to provide clarification in this answer what the provided code is actually doing.Durrell
E
6

From msdn:

The order of the returned file names is not guaranteed; use the Sort() method if a specific sort order is required.

The Sort() method is the standard Array.Sort(), which takes in IComparables (among other overloads), so if you sort by creation date, it will handle localization based on the machine settings.

Ec answered 9/9, 2008 at 20:36 Comment(0)
M
3

You are correct, the default is my name asc. The only way I have found to change the sort order it to create a datatable from the FileInfo collection.

You can then used the DefaultView from the datatable and sort the directory with the .Sort method.

This is quite involve and fairly slow but I'm hoping someone will post a better solution.

Mchale answered 9/9, 2008 at 20:38 Comment(1)
The default is the order the file system returns them in. If you're using NTFS, they will be alpha sorted, but if you're using FAT32, they will be returned in table order (i.e., more or less order of creation).Beautify
M
3

You can implement custom iComparer to do sorting. Read the file info for files and compare as you like.

IComparer comparer = new YourCustomComparer();
Array.Sort(System.IO.Directory.GetFiles(), comparer);

msdn info IComparer interface

Matland answered 9/9, 2008 at 20:45 Comment(0)
H
3

A more succinct VB.Net version...is very nice. Thank you. To traverse the list in reverse order, add the reverse method...

For Each fi As IO.FileInfo In filePaths.reverse
  ' Do whatever you wish here
Next
Hillock answered 12/12, 2013 at 16:14 Comment(0)
B
2

The MSDN Documentation states that there is no guarantee of any order on the return values. You have to use the Sort() method.

Boak answered 9/9, 2008 at 20:37 Comment(0)
L
2

You could write a custom IComparer interface to sort by creation date, and then pass it to Array.Sort. You probably also want to look at StrCmpLogical, which is what is used to do the sorting Explorer uses (sorting numbers correctly with text).

Lindie answered 9/9, 2008 at 20:41 Comment(0)
S
2

If you want to sort by something like creation date you probably need to use DirectoryInfo.GetFiles and then sort the resulting array using a suitable Predicate.

Sucking answered 9/9, 2008 at 20:42 Comment(0)
M
1

Just an idea. I like to find an easy way out and try re use already available resources. if I were to sort files I would've just create a process and make syscal to "DIR [x:\Folders\SubFolders*.*] /s /b /on" and capture the output.

With system's DIR command you can sort by :

/O          List by files in sorted order.
sortorder    N  By name (alphabetic)       S  By size (smallest first)
             E  By extension (alphabetic)  D  By date/time (oldest first)
             G  Group directories first    -  Prefix to reverse order

The /S switch includes sub folders

I AM NOT SURE IF D = By Date/Time is using LastModifiedDate or FileCreateDate. But if the needed sort order is already built-in in the DIR command, I will get that by calling syscall. And it's FAST. I am just the lazy guy ;)

After a little googling I found switch to sort by particular date/time:-

/t [[:]TimeField] : Specifies which time field to display or use for sorting. The following list describes each of the values you can use for TimeField. 

Value Description 
c : Creation
a : Last access
w : Last written
Mckale answered 31/3, 2010 at 17:34 Comment(0)
S
1

A more succinct VB.Net version, if anyone is interested

Dim filePaths As Linq.IOrderedEnumerable(Of IO.FileInfo) = _
  New DirectoryInfo("c:\temp").GetFiles() _
   .OrderBy(Function(f As FileInfo) f.CreationTime)
For Each fi As IO.FileInfo In filePaths
  ' Do whatever you wish here
Next
Steffin answered 21/3, 2013 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.