Gapotchenko.FX.IO
2022.2.7
Prefix Reserved
dotnet add package Gapotchenko.FX.IO --version 2022.2.7
NuGet\Install-Package Gapotchenko.FX.IO -Version 2022.2.7
<PackageReference Include="Gapotchenko.FX.IO" Version="2022.2.7" />
paket add Gapotchenko.FX.IO --version 2022.2.7
#r "nuget: Gapotchenko.FX.IO, 2022.2.7"
// Install Gapotchenko.FX.IO as a Cake Addin #addin nuget:?package=Gapotchenko.FX.IO&version=2022.2.7 // Install Gapotchenko.FX.IO as a Cake Tool #tool nuget:?package=Gapotchenko.FX.IO&version=2022.2.7
Overview
The module provides highly demanded input/output functionality that is missing in conventional .NET platform.
FileSystem
FileSystem
is a class provided by Gapotchenko.FX.IO
.
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 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 should 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)
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:
- 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
Or look at the full list of modules.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. 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. 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. net8.0 was computed. 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. |
.NET Core | netcoreapp2.0 is compatible. 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 | net46 is compatible. net461 was computed. 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. |
-
.NETCoreApp 2.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETCoreApp 2.1
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETCoreApp 3.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETFramework 4.6
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETFramework 4.7.1
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETFramework 4.7.2
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETStandard 2.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
.NETStandard 2.1
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
net5.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
net6.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
-
net7.0
- Gapotchenko.FX (>= 2022.2.7)
- Gapotchenko.FX.Text (>= 2022.2.7)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Gapotchenko.FX.IO:
Package | Downloads |
---|---|
Gapotchenko.FX.Profiles.Core
Represents the Core profile of Gapotchenko.FX. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2022.2.7 | 847 | 5/1/2022 |
2022.2.5 | 757 | 5/1/2022 |
2022.1.4 | 757 | 4/6/2022 |
2021.2.21 | 825 | 1/21/2022 |
2021.2.20 | 740 | 1/17/2022 |
2021.1.5 | 618 | 7/6/2021 |
2020.2.2-beta | 451 | 11/21/2020 |
2020.1.15 | 770 | 11/5/2020 |
2020.1.9-beta | 504 | 7/14/2020 |
2020.1.8-beta | 495 | 7/14/2020 |
2020.1.7-beta | 523 | 7/14/2020 |
2020.1.1-beta | 586 | 2/11/2020 |
2019.3.7 | 779 | 11/4/2019 |
2019.2.20 | 746 | 8/13/2019 |
2019.1.151 | 887 | 3/30/2019 |