Gapotchenko.FX.IO
2026.7.2
Prefix Reserved
dotnet add package Gapotchenko.FX.IO --version 2026.7.2
NuGet\Install-Package Gapotchenko.FX.IO -Version 2026.7.2
<PackageReference Include="Gapotchenko.FX.IO" Version="2026.7.2" />
<PackageVersion Include="Gapotchenko.FX.IO" Version="2026.7.2" />
<PackageReference Include="Gapotchenko.FX.IO" />
paket add Gapotchenko.FX.IO --version 2026.7.2
#r "nuget: Gapotchenko.FX.IO, 2026.7.2"
#:package Gapotchenko.FX.IO@2026.7.2
#addin nuget:?package=Gapotchenko.FX.IO&version=2026.7.2
#tool nuget:?package=Gapotchenko.FX.IO&version=2026.7.2
Overview
The module provides commonly demanded input/output functionality that is missing in baseline .NET platform.
FileSystem
FileSystem is a class provided by Gapotchenko.FX.IO module.
If offers extended I/O functions for file system,
and serves as an important addendum to a conventional System.IO namespace.
IsCaseSensitive
The FileSystem.IsCaseSensitive property shows whether the current host operating system uses case sensitive file names.
For example, Windows operating system uses case-insensitive file names,
so FileSystem.IsCaseSensitive returns false.
The same goes to macOS.
However, Linux and other Unix flavors use case-sensitive file names by default.
Whenever an app creates two files named Test.txt and test.txt,
those files are distinct and can coexist at the same folder.
FileSystem.IsCaseSensitive returns true on such operating systems.
PathComparer
FileSystem.PathComparer property returns a string comparer for file names.
Please take a look at the code below:
using Gapotchenko.FX.IO;
var files = new HashSet<string>(FileSystem.PathComparer);
files.Add("Test.txt");
files.Add("test.txt");
Console.WriteLine("Count of files: {0}", files.Count);
The given set would contain one entry on Windows, and two entries on Linux.
PathComparison
FileSystem.PathComparison property returns a StringComparison value that signifies a file name comparison mode used by the host OS.
It can be used in string comparison operations:
using Gapotchenko.FX.IO;
void ProcessFile(string filePath)
{
if (!filePath.EndsWith(".txt", FileSystem.PathComparison))
throw new Exception("Only text files can be processed.");
…
}
PathsAreEquivalent(string a, string b)
Determines whether the given paths are equivalent. If they point to the same file system entry then the method returns true; otherwise, false.
The problem this method solves is caused by the fact that a file path can be specified in multiple forms:
Test.txt(relative path)C:\Temp\Test.txt(absolute path)
Let's take a look at code:
using Gapotchenko.FX.IO;
Directory.SetCurrentDirectory(@"C:\Temp");
string fileA = "Test.txt";
string fileB = @"C:\Temp\Test.txt";
Console.WriteLine("String equality: {0}", string.Equals(fileA, fileB));
Console.WriteLine("Path equivalence: {0}", FileSystem.PathsAreEquivalent(fileA, fileB));
It produces the following results:
String equality: False
Path equivalence: True
Note that the file equivalence check is positive despite the different forms of a file path.
PathStartsWith(string path, string value)
Determines whether the beginning of the path matches the specified value in terms of the file system equivalence.
Say we have a folder name Contoso\Reports\2012\Final.
How do we know that it starts with Contoso\Reports?
A straightforward solution would be to use String.StartsWith function, like so:
bool IsContosoReportsFolder(string path) => path.StartsWith(@"Contoso\Reports");
It kind of works, until we try to pass something like Contoso\ReportsBackup.
The problem is that ReportsBackup is a very different folder than Reports, but the provided function returns true nevertheless.
We can cheat here, and try to use an updated function that adds a trailing slash:
bool IsContosoReportsFolder(string path) => path.StartsWith(@"Contoso\Reports\");
The problem is gone.
Until we ask for IsContosoReportsFolder("Contoso\Reports") value.
It is false now despite the fact that Contoso\Reports is literally the folder we are so eagerly looking for.
The correct solution is to use FileSystem.PathStartsWith method provided by Gapotchenko.FX.IO module:
using Gapotchenko.FX.IO;
bool IsContosoReportsFolder(string path) => FileSystem.PathStartsWith(path, @"Contoso\Reports");
It will now give the correct results for all inputs, even when they use alternative directory separators:
IsContosoReportsFolder(@"Contoso\ReportsBackup") => false
IsContosoReportsFolder(@"Contoso\Reports\2012\Final") => true
IsContosoReportsFolder(@"Contoso\Reports") => true
IsContosoReportsFolder(@"Contoso/Reports/2019/Progress") => true
WaitForFileWriteAccess(path)
FileSystem.WaitForFileWriteAccess method is a subtle but important primitive. It waits for a write access to the specified file.
Why would anyone want such a method? It turns out that a modern OS is a noisy environment that can put your app under a sledgehammer.
For example, if an app changes a file, it immediately grabs attention of various OS services. Anti-virus tools, search engines, file synchronization applications, all can lock the files for short and random time spans.
If a user of your app is unlucky or just uses an app frequently enough then he would occasionally get "File access denied" errors.
To minimize a possibility of such a congestion, you can call FileSystem.WaitForFileWriteAccess method before changing a file:
using Gapotchenko.FX.IO;
string fileName = "Results.txt";
FileSystem.WaitForFileWriteAccess(fileName);
File.WriteAllText(fileName, "A user can now use the app without occasional 'File access denied' errors.");
What it does is polls the file until write access is available. If the access is not there for 10 seconds, the method falls through.
More on this topic (Raymond Chen, "The Old New Thing" blog)
GetRealPath(path)
FileSystem.GetRealPath(string) method gets a canonicalized absolute path of the specified file system entry.
The method expands all symbolic links and resolves references to . and .. special directories.
It also normalizes consequent directory separators to the canonical form.
BitReader/BitWriter
BitReader and BitWriter classes provided by Gapotchenko.FX.IO extend the functionality of conventional BinaryReader and BinaryWriter by inheriting from them.
The conventional BinaryReader/BinaryWriter combo only supports little-endian byte order.
However, big-endian byte order is equally widespread.
This is how a big-endian binary reader can be created:
using Gapotchenko.FX;
using Gapotchenko.FX.IO;
var br = new BitReader(BigEndianBitConverter.Instance);
Thanks to the fact that BitReader is inherited from BinaryReader class, it is almost a drop-in replacement.
The same goes to BitWriter.
Commonly Used Types
Gapotchenko.FX.IO.FileSystemGapotchenko.FX.IO.BitReaderGapotchenko.FX.IO.BitWriter
Other Modules
Let's continue with a look at some other modules provided by Gapotchenko.FX:
- Gapotchenko.FX
- Gapotchenko.FX.AppModel.Information
- Gapotchenko.FX.Collections
- Gapotchenko.FX.Console
- Gapotchenko.FX.Data
- Gapotchenko.FX.Diagnostics
- ➴ Gapotchenko.FX.IO
- Gapotchenko.FX.Linq
- Gapotchenko.FX.Math
- Gapotchenko.FX.Memory
- Gapotchenko.FX.Security.Cryptography
- Gapotchenko.FX.Text
- Gapotchenko.FX.Threading
- Gapotchenko.FX.Tuples
- Gapotchenko.FX.Versioning
Or look at the full list of modules.
| Product | Versions 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. net6.0-windows7.0 is compatible. 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. net7.0-windows7.0 is compatible. 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. net8.0-windows7.0 is compatible. net9.0 is compatible. 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. net9.0-windows7.0 is compatible. net10.0 is compatible. 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. net10.0-windows7.0 is compatible. |
| .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 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. 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. |
-
.NETFramework 4.7.2
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
- System.Threading.Tasks.Extensions (>= 4.6.3)
-
.NETStandard 2.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
- System.Threading.Tasks.Extensions (>= 4.6.3)
-
.NETStandard 2.1
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net10.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net10.0-windows7.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net6.0-windows7.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net7.0-windows7.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net8.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net8.0-windows7.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net9.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
-
net9.0-windows7.0
- Gapotchenko.FX (>= 2026.7.2)
- Gapotchenko.FX.Text (>= 2026.7.2)
- Gapotchenko.FX.Threading (>= 2026.7.2)
NuGet packages (12)
Showing the top 5 NuGet packages that depend on Gapotchenko.FX.IO:
| Package | Downloads |
|---|---|
|
Gapotchenko.FX.Diagnostics.CommandLine
Provides primitives for command line manipulation. |
|
|
Gapotchenko.FX.Profiles.Core
Represents the Core profile of Gapotchenko.FX toolkit. |
|
|
Gapotchenko.FX.IO.Vfs
Provides a virtual file system (VFS) abstraction layer that enables uniform access to different file storage backends, including local file systems, archives, and custom storage formats. |
|
|
Gapotchenko.Shields.MSys2.Deployment
The deployment module of MSYS2 Shield. |
|
|
Gapotchenko.Shields.Cygwin.Deployment
The deployment module of Cygwin Shield. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.7.2 | 2,339 | 5/16/2026 |
| 2026.6.2 | 5,777 | 3/29/2026 |
| 2026.5.3 | 381 | 2/24/2026 |
| 2026.4.2 | 359 | 2/4/2026 |
| 2026.3.5 | 364 | 1/29/2026 |
| 2026.2.2 | 360 | 1/25/2026 |
| 2026.1.5 | 383 | 1/13/2026 |
| 2025.1.45 | 706 | 12/25/2025 |
| 2025.1.27-beta | 436 | 10/8/2025 |
| 2025.1.26-beta | 487 | 8/30/2025 |
| 2025.1.25-beta | 1,131 | 7/22/2025 |
| 2025.1.24-beta | 651 | 7/16/2025 |
| 2025.1.23-beta | 603 | 7/12/2025 |
| 2024.2.5 | 402 | 12/31/2024 |
| 2024.1.3 | 338 | 11/10/2024 |
| 2022.2.7 | 1,040 | 5/1/2022 |
| 2022.2.5 | 990 | 5/1/2022 |
| 2022.1.4 | 955 | 4/6/2022 |
| 2021.2.21 | 1,056 | 1/21/2022 |