Gapotchenko.FX.IO 2025.1.24-beta

Prefix Reserved
This is a prerelease version of Gapotchenko.FX.IO.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Gapotchenko.FX.IO --version 2025.1.24-beta
                    
NuGet\Install-Package Gapotchenko.FX.IO -Version 2025.1.24-beta
                    
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="Gapotchenko.FX.IO" Version="2025.1.24-beta" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Gapotchenko.FX.IO" Version="2025.1.24-beta" />
                    
Directory.Packages.props
<PackageReference Include="Gapotchenko.FX.IO" />
                    
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 Gapotchenko.FX.IO --version 2025.1.24-beta
                    
#r "nuget: Gapotchenko.FX.IO, 2025.1.24-beta"
                    
#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 Gapotchenko.FX.IO@2025.1.24-beta
                    
#: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=Gapotchenko.FX.IO&version=2025.1.24-beta&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Gapotchenko.FX.IO&version=2025.1.24-beta&prerelease
                    
Install as a Cake Tool

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.FileSystem
  • Gapotchenko.FX.IO.BitReader
  • Gapotchenko.FX.IO.BitWriter

Other Modules

Let's continue with a look at some other modules provided by Gapotchenko.FX:

Or look at the full list of modules.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net5.0-windows7.0 is compatible.  net6.0 is compatible.  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 is compatible.  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 is compatible.  netcoreapp2.2 was computed.  netcoreapp3.0 is compatible.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (9)

Showing the top 5 NuGet packages that depend on Gapotchenko.FX.IO:

Package Downloads
Gapotchenko.FX.Profiles.Core

Represents the Core profile of Gapotchenko.FX toolkit.

Gapotchenko.Shields.MSys2.Deployment

The deployment module of MSYS2 Shield.

Gapotchenko.Shields.Cygwin.Deployment

The deployment module of Cygwin Shield.

Gapotchenko.FX.Diagnostics.CommandShell

.NET polyfill to the future. A versatile RAD framework for .NET platform.

Gapotchenko.FX.IO.Vfs

.NET polyfill to the future. A versatile RAD framework for .NET platform.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2025.1.25-beta 479 7/22/2025
2025.1.24-beta 162 7/16/2025
2025.1.23-beta 253 7/12/2025
2024.2.5 233 12/31/2024
2024.1.3 202 11/10/2024
2022.2.7 921 5/1/2022
2022.2.5 833 5/1/2022
2022.1.4 825 4/6/2022
2021.2.21 897 1/21/2022
2021.2.20 817 1/17/2022
2021.1.5 687 7/6/2021
2020.2.2-beta 535 11/21/2020
2020.1.15 861 11/5/2020
2020.1.9-beta 581 7/14/2020
2020.1.8-beta 574 7/14/2020
2020.1.7-beta 603 7/14/2020
2020.1.1-beta 678 2/11/2020
2019.3.7 871 11/4/2019
2019.2.20 847 8/13/2019
2019.1.151 986 3/30/2019