TruePath 2.0.0

dotnet add package TruePath --version 2.0.0
                    
NuGet\Install-Package TruePath -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TruePath" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TruePath" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="TruePath" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TruePath --version 2.0.0
                    
#r "nuget: TruePath, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TruePath@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TruePath&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=TruePath&version=2.0.0
                    
Install as a Cake Tool

TruePath Status Ventis

This is a library containing a set of types to work with file system paths in .NET.

Motivation

Historically, .NET has been lacking a good set of types to work with file system paths. The System.IO.Path class has a variety of methods that operate on path strings, but it doesn't provide any types to represent paths themselves. It's impossible to tell whether a method accepts an absolute path, a relative path, a file name, or something file-related at all, only looking at its signature: all these types are represented by plain strings. Also, comparing different paths is not straightforward.

This library aims to fill this gap by providing a set of types that represent paths in a strongly-typed way. Now, you can require a path in a method's parameters, and it is guaranteed that the passed path will be well-formed and will have certain properties.

Also, the methods in the library provide some qualities that are missing from the System.IO.Path: say, we aim to provide several ways of path normalization and comparison, the ones that will and will not perform disk IO to resolve paths on case-insensitive file systems.

The library is inspired by the path libraries used in other ecosystems, in no particular order:

Read more on the documentation site.

If you miss some feature or have questions, do not hesitate to open an issue or go to the discussions section.

Packages

Name NuGet Package Documentation
TruePath TruePath on nuget.org API Reference
TruePath.SystemIo TruePath.SystemIo on nuget.org API Reference
TruePath.TestableIO.System.IO (third-party) TruePath.TestableIO.System.IO on nuget.org Documentation

TruePath provides two NuGet packages:

A third-party package, TruePath.TestableIO.System.IO, adds TestableIO.System.IO.Abstractions integration on top of TruePath.

Versioning

This project follows Semantic Versioning, with one exception: the behavior of the types and members marked as [System.Diagnostics.CodeAnalysis.ExperimentalAttribute] may change without a major version bump. Using them causes the compiler to report diagnostic TRUEPATH001; suppress it (e.g. by adding <NoWarn>$(NoWarn);TRUEPATH001</NoWarn> into your project file, or with #pragma warning disable TRUEPATH001) to acknowledge that.

Documentation

License

The project is distributed under the terms of the MIT license.

The license indication in the project's sources is compliant with the REUSE specification v3.3.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (13)

Showing the top 5 NuGet packages that depend on TruePath:

Package Downloads
TruePath.SystemIo

Adapters to use System.IO.File and System.IO.Directory APIs together with TruePath.

Generaptor

Package Description

FileBasedApp.Toolkit

Opiniated helpers for a FileBaseApp. Based on TruePath, SimpleExec and Spectre.Console.Cli

TruePath.TestableIO.System.IO

Bridges TruePath and TestableIO.System.IO Presents extension methods for the Testable.System.IO mapping to AbsoutePath (TruePath)

Fenrir.Git

Fenrir is a .NET library to work with Git repositories. It provides functions to read Git objects, traverse the commit graph, extract trees and files from any commit, etc. Essentially, it provides tools to create your own Git client, or transform a repository in any way.

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on TruePath:

Repository Stars
ForNeVeR/Cesium
C compiler for the CLI platform
Version Downloads Last Updated
2.0.0 703 10/25/2026
1.12.0 33,622 3/14/2026
1.11.0 12,533 11/25/2025
1.10.0 7,195 8/4/2025
1.9.0 9,295 5/31/2025
1.8.0 390 5/31/2025
1.7.0 1,815 4/18/2025
1.6.0 3,859 10/6/2024
1.5.0 1,115 9/22/2024
1.4.0 918 8/11/2024
1.3.0 805 6/21/2024
1.2.1 465 5/25/2024
1.2.0 397 5/5/2024
1.1.0 470 4/27/2024
1.0.0 287 4/21/2024
0.0.0 256 4/20/2024

This is a major release with certain breaking changes. No public APIs have been broken, but the amount of minor behavior changes required us to bump the major version.

The main change (outlined below) is the introduction of the relative path kinds (most important for Windows). TruePath's path resolve APIs now follow the new rules regarding the relative path resolve (especially regarding more exotic relative path kinds on Windows); check the relevant documentation.

Another notable change is that, while LocalPath still considers an empty path to designate the current directory, current directory now always gets normalized as "." and not an empty string.

There were a bunch of unrelated important (sometimes breaking) changes to other APIs, read the details below.

[Changed]

- Breaking: (#224 (https://github.com/ForNeVeR/TruePath/issues/224)) on Windows, LocalPath.IsAbsolute now only returns true for fully qualified paths, such as C:\Windows. Paths rooted without a drive letter (\Windows), and paths relative to the current directory of a drive (C:Windows, C:) are not absolute anymore, and AbsolutePath now rejects them. Previously, this was following the Path.IsPathRooted API.
- Breaking: (#224 (https://github.com/ForNeVeR/TruePath/issues/224)) on Windows, the / operator of LocalPath and AbsolutePath no longer delegates to Path.Combine, and instead follows the algorithm of C++ std::filesystem::path::operator/ (fs.path.append (https://eel.is/c++draft/fs.path.append)) with case-insensitive drive letters. In particular, C:\base / \x is now C:\x (was \x), C:\base / C:x is now C:\base\x (was C:x), and C: / x is now C:x (was C:\x). On Unix, the behavior is unchanged.
- Breaking: path normalization now represents the current directory as . instead of an empty string: PathStrings.Normalize returns "." for "", "." and "a/..", and so do LocalPath.Value and ToString() (and LocalPath.Parent of a single-segment relative path is .). As a consequence, LocalPath.FileName of such a path is ., the same way it is .. for .., and GetExtensionWithDot returns . for it.
- Breaking: LocalPath.IsPrefixOf and StartsWith now consider paths of different PathKind unrelated: an absolute path is never a prefix of a relative one, nor the other way round, and on Windows \Windows, C:Windows and Windows are all unrelated to each other.
- Breaking: PathExtensions.WithExtension now throws an ArgumentException unless the path ends with a file name and the result of the change is a file name in its place: an extension change may no longer alter the number or the kind of any path's segments. It used to do so, e.g.:
- new LocalPath(@"C:\foo\.gitignore").WithExtension(null) returned C:\foo,
- new LocalPath(".gitignore").WithExtension(null) returned the empty path,
- and new LocalPath(@"C:\").WithExtension("bar") returned C:\.bar.
None of the examples above take place anymore.
- #224 (https://github.com/ForNeVeR/TruePath/issues/224): on Windows, AbsolutePath / LocalPath now resolves a path relative to the current directory of another drive against the current directory of that drive, so the result is always absolute: e.g. C:\base / D:x is D:\x if the current directory of drive D: is its root. Previously, the result was D:x, which is not absolute.
- #224 (https://github.com/ForNeVeR/TruePath/issues/224): on Windows, LocalPath.ResolveToCurrentDirectory now resolves \x against the drive of the current directory, and D:x against the current directory of drive D:.
- #240 (https://github.com/ForNeVeR/TruePath/issues/240): more performant AbsolutePath.ReadKind: it now queries the entry attributes only once, and on Windows it no longer allocates or performs additional IO in cases not concerning reparse points. Thanks to @FalconTechDev for help!
- AbsolutePath.ReadKind now only returns null if the entry doesn't exist, and throws an exception if its attributes cannot be read for another reason: e.g. an UnauthorizedAccessException if the access is denied, or an IOException if the path contains a name rejected by the file system (on .NET Framework, also ArgumentException or PathTooLongException). Previously, it returned null in these cases.
- The platform-default path comparers (LocalPath.PlatformDefaultComparer, AbsolutePath.PlatformDefaultComparer) are now case-insensitive on iOS and tvOS as well, matching the .NET runtime.

[Added]

- #215 (https://github.com/ForNeVeR/TruePath/issues/215): AbsolutePath.PathRoot property. Thanks to @fskalkan!
- LocalPath.PathRoot property, similar to the previous entry, returning the root of an absolute path, or the drive root of a drive-relative path (e.g. C:foo, which only exists on Windows, will return C:), or null when the root can't be determined.
- #202: path.GetFiles(LocalPathPattern) (https://github.com/ForNeVeR/TruePath/issues/202). Thanks to @hamdiakin!
- #224 (https://github.com/ForNeVeR/TruePath/issues/224): PathKind enumeration and LocalPath.Kind property, telling an absolute path from a relative one, and on Windows also from a path rooted without a drive letter (\Windows) and from a path relative to the current directory of a drive (C:Windows). These are experimental (diagnostic TRUEPATH001): more kinds may be added later, e.g. for UNC paths.

[Fixed]

- #239 (https://github.com/ForNeVeR/TruePath/issues/239): on Unix, AbsolutePath.Canonicalize() no longer closes the file descriptor 0 when the path doesn't exist. This used to close the standard input of the process, or any file or socket that later took this descriptor number. Also, it no longer leaks the memory allocated for the resolved path.
- #217 (https://github.com/ForNeVeR/TruePath/issues/217): the IsPrefixOf and StartsWith methods for both LocalPath and AbsolutePath are now exact opposites (use same code), and always operate on whole path segments (file and directory names) instead of raw strings. For example, new AbsolutePath("/foo1").StartsWith(new AbsolutePath("/foo")) is now false, where it used to be true. Thanks to @berkcantmr for help on this fix!
- #221 (https://github.com/ForNeVeR/TruePath/issues/221): IsPrefixOf now handles the root folders correctly as prefixes of all the absolute paths under the same root. Thanks to @berkcantmr and @t957095!
- IsPrefixOf and StartsWith now compare path strings using ordinal string comparison.
- #225 (https://github.com/ForNeVeR/TruePath/issues/225): IsPrefixOf and StartsWith now compare path strings using the same platform-default case sensitivity as path equality. Thanks to @amirani8137!
- #224 (https://github.com/ForNeVeR/TruePath/issues/224): path normalization no longer drops the root separator when a rooted path ends with ..: C:\base\.. is now normalized to C:\ (was C:, a path relative to the current directory of drive C:), and /base/.. to / (was an empty path, i.e. the current directory).
- #219 (https://github.com/ForNeVeR/TruePath/issues/219): path normalization no longer applies Windows drive-specific logic to all paths. Thanks to @hamdiakin!
- #95 (https://github.com/ForNeVeR/TruePath/issues/95): Path normalization now drops a .. directly after the root, since the root has no parent: /.. is normalized to /, and C:\..\x to C:\x, the same as Path.GetFullPath does. Thanks to @sinthu-14 for help!
- #226 (https://github.com/ForNeVeR/TruePath/issues/226): LocalPath.IsPrefixOf and StartsWith now take leading .. references of relative paths into account instead of comparing them as strings. For example, new LocalPath("..").IsPrefixOf(new LocalPath("foo")) is now true, and new LocalPath("..").IsPrefixOf(new LocalPath("../..")) is now false. Thanks to @rghvgrv!
- In .NET Standard 2.0's version of TruePath (e.g., the one targeting .NET Framework), LocalPath.RelativeTo and AbsolutePath.RelativeTo now use a port of the .NET runtime's Path.GetRelativePath, and return the same results as on .NET 8+ (except for the stream syntax, see #235 (https://github.com/ForNeVeR/TruePath/issues/235)). Previously, the result was wrong for a destination equal to or above the base path, and for names containing %XX sequences.
- AbsolutePath.ReadKind no longer throws an exception if the entry gets deleted during the call.
- LocalPath.RelativeTo no longer throws an exception when either path designates the current directory.