dotnet / dotnet/runtime

[API Proposal]: Add new constructors to FileSystemEnumerable and FileSystemEnumerator allowing a search pattern string to be provided

Open
#127,692 4 comments 0 reactions 0 assignees View on GitHub
api-suggestion area-System.IO
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Background and motivation

`DirectoryInfo.GetFiles` and related functions have a `searchPattern` string parameter for matching the file name. Historically, this matching was done in managed code (not at the OS-level), therefore it wasn't really necessary for `FileSystemEnumerator`/`FileSystemEnumerable` to take a search pattern string since matching could be done in the filter predicate. However, the OS (at least Windows), supports doing this filtering at the OS level, and this OS-level filtering is now implemented by https://github.com/dotnet/runtime/pull/122947. Thus it is now much faster to use `DirectoryInfo.GetFiles` in a scenario where a search pattern applies (e.g. filtering by a single file extension), even though `FileSystemEnumerator`/`FileSystemEnumerable` are meant to be the most performant methods. Therefore I propose they should accept a search pattern string. The implementation should be quite easy since there is now an internal constructor for `FileSystemEnumerator`/`FileSystemEnumerable` which accepts the search pattern (for Windows - for other OSes it would have to make use of the matching filter used by `DirectoryInfo`, which should also be quite straightforward).

For reference, see related discussion here - https://github.com/dotnet/runtime/discussions/127501.

### API Proposal

```csharp
namespace System.IO.Enumeration;

public abstract class FileSystemEnumerator : System.Runtime.ConstrainedExecution.CriticalFinalizerObject, System.Collections.Generic.IEnumerator
{
//Added searchPattern parameter to existing constructor
public FileSystemEnumerator(string directory, System.IO.EnumerationOptions? options = default, string? searchPattern = default);
}

public class FileSystemEnumerable : System.Collections.Generic.IEnumerable
{
//Added searchPattern parameter to existing constructor
public FileSystemEnumerable(string directory, System.IO.Enumeration.FileSystemEnumerable.FindTransform transform, System.IO.EnumerationOptions? options = default, string? searchPattern = default);
}
```

The searchPattern is in the same format as for [DirectoryInfo.GetFiles](https://learn.microsoft.com/en-us/dotnet/api/system.io.directoryinfo.getfiles?view=net-10.0).

### API Usage

```csharp
var enumeration = new FileSystemEnumerable(
directory: Path.GetTempPath(), // search Temp directory
transform: (ref FileSystemEntry entry) => entry.ToFullPath(), // map FileSystemEntry to string (see FileSystemEnumerable generic argument)
options: new EnumerationOptions()
{
RecurseSubdirectories = true
},
searchPattern: "*.tmp")
{
// The following predicate will be used to filter the file entries
ShouldIncludePredicate = (ref FileSystemEntry entry) => !entry.IsDirectory
};
```
This is taken from the [FileSystemEnumerable](https://learn.microsoft.com/en-us/dotnet/api/system.io.enumeration.filesystemenumerable-1?view=net-10.0) example and replaces the manual extension filter with a search pattern, which on Windows is now applied at the OS level.

### Alternative Designs

Could make the searchPattern a property of `FileSystemEnumerable`/`FileSystemEnumerator` instead.

### Risks

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.