IniFileNet 0.8.0
dotnet add package IniFileNet --version 0.8.0
NuGet\Install-Package IniFileNet -Version 0.8.0
<PackageReference Include="IniFileNet" Version="0.8.0" />
<PackageVersion Include="IniFileNet" Version="0.8.0" />
<PackageReference Include="IniFileNet" />
paket add IniFileNet --version 0.8.0
#r "nuget: IniFileNet, 0.8.0"
#:package IniFileNet@0.8.0
#addin nuget:?package=IniFileNet&version=0.8.0
#tool nuget:?package=IniFileNet&version=0.8.0
IniFileNet
A .NET Library for reading and writing ini files.
Usage
Note that because this package is currently not at 1.0 yet, this may change. Below is some example code.
The IniStreamReader class lets you read individual sections, keys and values, and comments. This is ideal when you want fine control and handling over the parts of the ini file.
The IniStreamSectionReader wraps that class and groups keys and values up into sections for you. This is useful when you want to handle individual sections manually, and is fairly concise.
The IniDictionaryReader can read the entirety of a file into a Dictionary, keyed by strings. The value is typically either string or List<string>, but can be made anything you want.
You can use instances of IIniValueAcceptor to accept values with specific keys from a section, which helps parsing destination types and validating that everything loads correctly.
Example ini File 1
[GUI]
scaling factor = 1
subtitles = true
colour topic enable = true
[Map]
allow zooming = true
global = true
IniDictionaryReader Usage
using (IniStreamReader iniIn = new IniStreamReader(new StreamReader(new FileStream(args[0], FileMode.Open, FileAccess.Read), Encoding.UTF8), DefaultIniTextEscaper.Default, new IniReaderOptions(ignoreComments: true, trimKeys: true, trimValues: true)))
{
// You can pass in your own dictionary. Or use the parameterless constructor, which makes a dictionary for you
IniDictionaryReader<string> reader = new();
// Load with the delegate that only allows unique keys. The full keys are like: Section.Key
reader.Load(iniIn, IniDictionaryReader.StringSingle).ThrowIfError();
Dictionary<string, string> dict = reader.Dictionary;
// This single dictionary for an entire ini stream tends to work better if everything is uniquely addressed.
// For our example this works great, but ini files with repeating similar sections may be better served by the below examples.
// We trimmed our values and keys using the options
string scalingFactor = dict["GUI.scaling factor"];
string subtitles = dict["GUI.subtitles"];
string colourTopicEnable = dict["GUI.colour topic enable"];
string allowZooming = dict["Map.allow zooming"];
string global = dict["Map.global"];
}
Example ini File 2
[Section1]
Url=https://example.com
OutputTemplate=Hello there {{Person}}, how are you?
Attempts=5
Ask=true
Regex=PersonName:(.+)
LastSeen=2005-07-12T12:41:00Z
[Section2]
Url=https://example.com
OutputTemplate=Hello there {{Person}}, how are you?
Attempts=5
Ask=true
Regex=PersonName:(.+)
LastSeen=2005-07-12T12:41:00Z
[Section3]
Url=https://example.com
OutputTemplate=Hello there {{Person}}, how are you?
Attempts=5
Ask=true
Regex=PersonName:(.+)
LastSeen=2005-07-12T12:41:00Z
IniStreamSectionReader Usage
List<Target> targets = [];
using (IniStreamSectionReader iniIn = new(new IniStreamReader(new StreamReader(new FileStream(args[0], FileMode.Open, FileAccess.Read), Encoding.UTF8), DefaultIniTextEscaper.Default, new IniReaderOptions(ignoreComments: true))))
{
// Coding like this emphasizes turning IniErrors into Exceptions and throwing them, which can be useful for concise code if an error in loading an ini file should mean the app crashes (or the Exception gets caught)
while (iniIn.Error.Code == IniErrorCode.None)
{
// Reads a section and throws an exception on any error
SectionAsDictionary section = iniIn.ReadNewSectionDictionary(DuplicateKeyBevahiour.Error).ValueOrException();
// Ignore global properties
if (section.Name == "") continue;
Dictionary<string, string> keyValues = section.KeyValues;
targets.Add(new Target
(
name: section.Name,
url: keyValues["Url"],
outputTemplate: keyValues["OutputTemplate"],
ask: bool.Parse(keyValues["Ask"]),
attempts: int.Parse(keyValues["Attempts"]),
regex: new Regex(keyValues["Regex"]),
lastSeen: DateTimeOffset.Parse(keyValues["LastSeen"])
));
}
iniIn.Error.ThrowIfError();
}
IIniValueAcceptor Usage
List<Target> targets = [];
using (IniStreamSectionReader iniIn = new(new IniStreamReader(new StreamReader(new FileStream(args[0], FileMode.Open, FileAccess.Read), Encoding.UTF8), DefaultIniTextEscaper.Default, new IniReaderOptions(ignoreComments: true))))
{
IniValueAcceptorDictionaryBuilder b = new(new Dictionary<string, IIniValueAcceptor>(StringComparer.OrdinalIgnoreCase));
IniValueAcceptorOnlyLast url = b.OnlyLast("Url");
IniValueAcceptorOnlyFirst outputTemplate = b.OnlyFirst("OutputTemplate");
IniValueAcceptorSingle<int> attempts = b.Single("Attempts", IniParse.Int32);
IniValueAcceptorSingle<bool> ask = b.Single("Ask", IniParse.Boolean);
IniValueAcceptorOnlyLast<Regex?> regex = b.OnlyLast("Regex", (string value) =>
{
try
{
return new IniResult<Regex?>(new Regex(value), default);
}
catch (Exception ex)
{
return new IniResult<Regex?>(null, new IniError(IniErrorCode.ValueInvalid, string.Concat("Could not parse \"", value, "\" as Regex: ", ex.Message)));
}
});
IniValueAcceptorOnlyLast<DateTimeOffset> lastSeen = b.OnlyLast("LastSeen", (string value) => DateTimeOffset.TryParse(value, out var r)
? new IniResult<DateTimeOffset>(r, default)
: new IniResult<DateTimeOffset>(default, new(IniErrorCode.ValueInvalid, string.Concat("Could not parse \"", value, "\" as DateTimeOffset"))));
Dictionary<string, IIniValueAcceptor> acceptors = b.Acceptors;
while (iniIn.NextSection())
{
ReadOnlyIniSection section = iniIn.Section;
IniError err = section.AcceptAll(acceptors);
// Can explicitly do it this way
if (err.Code != default)
{
Console.WriteLine("Error reading ini file: " + err.Msg);
throw err.ToException();
}
// Or just call this
err.ThrowIfError();
targets.Add(new Target
(
name: section.Name,
url: url.ValueOrException(),
outputTemplate: outputTemplate.ValueOrException(),
attempts: attempts.Value,
ask: ask.Value,
regex: regex.Value,
lastSeen: lastSeen.Value
));
IniUtil.ResetAll(acceptors.Values);
}
iniIn.Error.ThrowIfError();
}
| 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. 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 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. 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. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Added some IniStreamHandlers, for simpler loading of ini files into Dictionaries.
- Breaking change: Behaviour when options are set to allow line continuations and allow value escapes differs when there is a trailing backslash at the end of the file. Previously this would issue an error as it was interpreted as an incomplete escape sequence. Now, it is interpreted as a trailing line continuation, and no error is raised.