Initial commit

This commit is contained in:
Mark J Price 2022-03-04 08:34:29 +00:00
parent 17ad36d6ad
commit 3d241b2154
44 changed files with 1619 additions and 0 deletions

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
namespace Packt.Shared;
public class Circle : Shape
{
public override double Area
{
get
{
return Math.PI * Radius * Radius;
}
}
public double Radius { get; set; }
}

View file

@ -0,0 +1,50 @@
using Packt.Shared; // Circle, Rectangle, Shape
using System.Xml.Serialization; // XmlSerializer
using static System.Environment;
using static System.IO.Path;
// create a file path to write to
string path = Combine(CurrentDirectory, "shapes.xml");
// create a list of Shape objects to serialize
List<Shape> listOfShapes = new()
{
new Circle { Colour = "Red", Radius = 2.5 },
new Rectangle { Colour = "Blue", Height = 20.0, Width = 10.0 },
new Circle { Colour = "Green", Radius = 8 },
new Circle { Colour = "Purple", Radius = 12.3 },
new Rectangle { Colour = "Blue", Height = 45.0, Width = 18.0 }
};
// create an object that knows how to serialize and deserialize
// a list of Shape objects
XmlSerializer serializerXml = new(listOfShapes.GetType());
WriteLine("Saving shapes to XML file:");
using (FileStream fileXml = File.Create(path))
{
serializerXml.Serialize(fileXml, listOfShapes);
}
WriteLine("Loading shapes from XML file:");
List<Shape>? loadedShapesXml = null;
using (FileStream fileXml = File.Open(path, FileMode.Open))
{
loadedShapesXml =
serializerXml.Deserialize(fileXml) as List<Shape>;
}
if (loadedShapesXml == null)
{
WriteLine($"{nameof(loadedShapesXml)} is empty.");
}
else
{
foreach (Shape item in loadedShapesXml)
{
WriteLine($"{item.GetType().Name} is {item.Colour} and has an area of {item.Area:N2}");
}
}

View file

@ -0,0 +1,15 @@
namespace Packt.Shared;
public class Rectangle : Shape
{
public override double Area
{
get
{
return Height * Width;
}
}
public double Height { get; set; }
public double Width { get; set; }
}

View file

@ -0,0 +1,11 @@
using System.Xml.Serialization;
namespace Packt.Shared;
[XmlInclude(typeof(Circle))]
[XmlInclude(typeof(Rectangle))]
public abstract class Shape
{
public string? Colour { get; set; }
public abstract double Area { get; }
}

View file

@ -0,0 +1,55 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32210.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkingWithFileSystems", "WorkingWithFileSystems\WorkingWithFileSystems.csproj", "{FCC1830B-5341-4ED6-B9B3-1885B1724D6E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkingWithStreams", "WorkingWithStreams\WorkingWithStreams.csproj", "{3D9CAC15-E6F2-462E-9821-45BEF1A76326}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkingWithEncodings", "WorkingWithEncodings\WorkingWithEncodings.csproj", "{70A9750E-5C55-4879-B601-20AC5F6CDCB4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithSerialization", "WorkingWithSerialization\WorkingWithSerialization.csproj", "{7493AA42-910F-4FB2-B3D4-34553255BD54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithJson", "WorkingWithJson\WorkingWithJson.csproj", "{CA13AF96-7EE4-42C4-A671-C373E218726A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch09Ex02SerializingShapes", "Ch09Ex02SerializingShapes\Ch09Ex02SerializingShapes.csproj", "{27FA94CC-1856-4512-9D09-0214CF846311}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FCC1830B-5341-4ED6-B9B3-1885B1724D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FCC1830B-5341-4ED6-B9B3-1885B1724D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCC1830B-5341-4ED6-B9B3-1885B1724D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FCC1830B-5341-4ED6-B9B3-1885B1724D6E}.Release|Any CPU.Build.0 = Release|Any CPU
{3D9CAC15-E6F2-462E-9821-45BEF1A76326}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D9CAC15-E6F2-462E-9821-45BEF1A76326}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D9CAC15-E6F2-462E-9821-45BEF1A76326}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D9CAC15-E6F2-462E-9821-45BEF1A76326}.Release|Any CPU.Build.0 = Release|Any CPU
{70A9750E-5C55-4879-B601-20AC5F6CDCB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70A9750E-5C55-4879-B601-20AC5F6CDCB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70A9750E-5C55-4879-B601-20AC5F6CDCB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70A9750E-5C55-4879-B601-20AC5F6CDCB4}.Release|Any CPU.Build.0 = Release|Any CPU
{7493AA42-910F-4FB2-B3D4-34553255BD54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7493AA42-910F-4FB2-B3D4-34553255BD54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7493AA42-910F-4FB2-B3D4-34553255BD54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7493AA42-910F-4FB2-B3D4-34553255BD54}.Release|Any CPU.Build.0 = Release|Any CPU
{CA13AF96-7EE4-42C4-A671-C373E218726A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA13AF96-7EE4-42C4-A671-C373E218726A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA13AF96-7EE4-42C4-A671-C373E218726A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA13AF96-7EE4-42C4-A671-C373E218726A}.Release|Any CPU.Build.0 = Release|Any CPU
{27FA94CC-1856-4512-9D09-0214CF846311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27FA94CC-1856-4512-9D09-0214CF846311}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27FA94CC-1856-4512-9D09-0214CF846311}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27FA94CC-1856-4512-9D09-0214CF846311}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {285FD445-B8EB-4756-9152-F155A7861DD8}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,51 @@
using Packt.Shared;
using System.Text;
WriteLine("Encodings");
WriteLine("[1] ASCII");
WriteLine("[2] UTF-7");
WriteLine("[3] UTF-8");
WriteLine("[4] UTF-16 (Unicode)");
WriteLine("[5] UTF-32");
WriteLine("[6] Latin1");
WriteLine("[any other key] Default encoding");
WriteLine();
// choose an encoding
Write("Press a number to choose an encoding.");
ConsoleKey number = ReadKey(intercept: true).Key;
WriteLine(); WriteLine();
Encoding encoder = number switch
{
ConsoleKey.D1 or ConsoleKey.NumPad1 => Encoding.ASCII,
ConsoleKey.D2 or ConsoleKey.NumPad2 => Encoding.UTF7,
ConsoleKey.D3 or ConsoleKey.NumPad3 => Encoding.UTF8,
ConsoleKey.D4 or ConsoleKey.NumPad4 => Encoding.Unicode,
ConsoleKey.D5 or ConsoleKey.NumPad5 => Encoding.UTF32,
ConsoleKey.D6 or ConsoleKey.NumPad6 => Encoding.Latin1,
_ => Encoding.Default
};
// define a string to encode
string message = "Café £4.39";
WriteLine($"Text to encode: {message} Characters: {message.Length}");
// encode the string into a byte array
byte[] encoded = encoder.GetBytes(message);
// check how many bytes the encoding needed
WriteLine("{0} used {1:N0} bytes.",
encoder.GetType().Name, encoded.Length);
WriteLine();
// enumerate each byte
WriteLine($"BYTE | HEX | CHAR");
foreach (byte b in encoded)
{
WriteLine($"{b,4} | {b.ToString("X"),3} | {(char)b,4}");
}
// decode the byte array back into a string and display it
string decoded = encoder.GetString(encoded);
WriteLine(decoded);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
partial class Program
{
static void SectionTitle(string title)
{
ConsoleColor previousColor = ForegroundColor;
ForegroundColor = ConsoleColor.Yellow;
WriteLine("*");
WriteLine($"* {title}");
WriteLine("*");
ForegroundColor = previousColor;
}
}

View file

@ -0,0 +1,132 @@
using static System.IO.Directory;
using static System.IO.Path;
using static System.Environment;
SectionTitle("Handling cross-platform environments and filesystems");
WriteLine("{0,-33} {1}", arg0: "Path.PathSeparator",
arg1: PathSeparator);
WriteLine("{0,-33} {1}", arg0: "Path.DirectorySeparatorChar",
arg1: DirectorySeparatorChar);
WriteLine("{0,-33} {1}", arg0: "Directory.GetCurrentDirectory()",
arg1: GetCurrentDirectory());
WriteLine("{0,-33} {1}", arg0: "Environment.CurrentDirectory",
arg1: CurrentDirectory);
WriteLine("{0,-33} {1}", arg0: "Environment.SystemDirectory",
arg1: SystemDirectory);
WriteLine("{0,-33} {1}", arg0: "Path.GetTempPath()",
arg1: GetTempPath());
WriteLine("GetFolderPath(SpecialFolder");
WriteLine("{0,-33} {1}", arg0: " .System)",
arg1: GetFolderPath(SpecialFolder.System));
WriteLine("{0,-33} {1}", arg0: " .ApplicationData)",
arg1: GetFolderPath(SpecialFolder.ApplicationData));
WriteLine("{0,-33} {1}", arg0: " .MyDocuments)",
arg1: GetFolderPath(SpecialFolder.MyDocuments));
WriteLine("{0,-33} {1}", arg0: " .Personal)",
arg1: GetFolderPath(SpecialFolder.Personal));
SectionTitle("Managing drives");
WriteLine("{0,-30} | {1,-10} | {2,-7} | {3,18} | {4,18}",
"NAME", "TYPE", "FORMAT", "SIZE (BYTES)", "FREE SPACE");
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
if (drive.IsReady)
{
WriteLine(
"{0,-30} | {1,-10} | {2,-7} | {3,18:N0} | {4,18:N0}",
drive.Name, drive.DriveType, drive.DriveFormat,
drive.TotalSize, drive.AvailableFreeSpace);
}
else
{
WriteLine("{0,-30} | {1,-10}", drive.Name, drive.DriveType);
}
}
SectionTitle("Managing directories");
// define a directory path for a new folder
// starting in the user's folder
string newFolder = Combine(
GetFolderPath(SpecialFolder.Personal), "NewFolder");
WriteLine($"Working with: {newFolder}");
// check if it exists
WriteLine($"Does it exist? {Exists(newFolder)}");
// create directory
WriteLine("Creating it...");
CreateDirectory(newFolder);
WriteLine($"Does it exist? {Exists(newFolder)}");
Write("Confirm the directory exists, and then press ENTER: ");
ReadLine();
// delete directory
WriteLine("Deleting it...");
Delete(newFolder, recursive: true);
WriteLine($"Does it exist? {Exists(newFolder)}");
SectionTitle("Managing files");
// define a directory path to output files
// starting in the user's folder
string dir = Combine(
GetFolderPath(SpecialFolder.Personal), "OutputFiles");
CreateDirectory(dir);
// define file paths
string textFile = Combine(dir, "Dummy.txt");
string backupFile = Combine(dir, "Dummy.bak");
WriteLine($"Working with: {textFile}");
// check if a file exists
WriteLine($"Does it exist? {File.Exists(textFile)}");
// create a new text file and write a line to it
StreamWriter textWriter = File.CreateText(textFile);
textWriter.WriteLine("Hello, C#!");
textWriter.Close(); // close file and release resources
WriteLine($"Does it exist? {File.Exists(textFile)}");
// copy the file, and overwrite if it already exists
File.Copy(sourceFileName: textFile,
destFileName: backupFile, overwrite: true);
WriteLine(
$"Does {backupFile} exist? {File.Exists(backupFile)}");
Write("Confirm the files exist, and then press ENTER: ");
ReadLine();
// delete file
File.Delete(textFile);
WriteLine($"Does it exist? {File.Exists(textFile)}");
// read from the text file backup
WriteLine($"Reading contents of {backupFile}:");
StreamReader textReader = File.OpenText(backupFile);
WriteLine(textReader.ReadToEnd());
textReader.Close();
SectionTitle("Managing paths");
WriteLine($"Folder Name: {GetDirectoryName(textFile)}");
WriteLine($"File Name: {GetFileName(textFile)}");
WriteLine("File Name without Extension: {0}",
GetFileNameWithoutExtension(textFile));
WriteLine($"File Extension: {GetExtension(textFile)}");
WriteLine($"Random File Name: {GetRandomFileName()}");
WriteLine($"Temporary File Name: {GetTempFileName()}");
SectionTitle("Getting file information ");
FileInfo info = new(backupFile);
WriteLine($"{backupFile}:");
WriteLine($"Contains {info.Length} bytes");
WriteLine($"Last accessed {info.LastAccessTime}");
WriteLine($"Has readonly set to {info.IsReadOnly}");

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,23 @@
using System.Text.Json.Serialization; // [JsonInclude]
public class Book
{
// constructor to set non-nullable property
public Book(string title)
{
Title = title;
}
// properties
public string Title { get; set; }
public string? Author { get; set; }
// fields
[JsonInclude] // include this field
public DateTime PublishDate;
[JsonInclude] // include this field
public DateTimeOffset Created;
public ushort Pages;
}

View file

@ -0,0 +1,39 @@
using System.Text.Json; // JsonSerializer
using static System.Environment;
using static System.IO.Path;
Book mybook = new(title:
"C# 11 and .NET 7 - Modern Cross-platform Development")
{
Author = "Mark J Price",
PublishDate = new(year: 2022, month: 11, day: 8),
Pages = 823,
Created = DateTimeOffset.UtcNow,
};
JsonSerializerOptions options = new()
{
/*
IncludeFields = true, // includes all fields
PropertyNameCaseInsensitive = true,
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
*/
};
string filePath = Combine(CurrentDirectory, "mybook.json");
using (Stream fileStream = File.Create(filePath))
{
JsonSerializer.Serialize<Book>(
utf8Json: fileStream, value: mybook, options);
}
WriteLine("Written {0:N0} bytes of JSON to {1}",
arg0: new FileInfo(filePath).Length,
arg1: filePath);
WriteLine();
// Display the serialized object graph
WriteLine(File.ReadAllText(filePath));

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,26 @@
using System.Xml.Serialization; // [XmlAttribute]
namespace Packt.Shared;
public class Person
{
public Person() { }
public Person(decimal initialSalary)
{
Salary = initialSalary;
}
[XmlAttribute("fname")]
public string? FirstName { get; set; }
[XmlAttribute("lname")]
public string? LastName { get; set; }
[XmlAttribute("dob")]
public DateTime DateOfBirth { get; set; }
public HashSet<Person>? Children { get; set; }
protected decimal Salary { get; set; }
}

View file

@ -0,0 +1,117 @@
using System.Xml.Serialization; // XmlSerializer
using Packt.Shared; // Person
using NewJson = System.Text.Json.JsonSerializer;
using static System.Environment;
using static System.IO.Path;
// create an object graph
List<Person> people = new()
{
new(30000M)
{
FirstName = "Alice",
LastName = "Smith",
DateOfBirth = new(year: 1974, month: 3, day: 14)
},
new(40000M)
{
FirstName = "Bob",
LastName = "Jones",
DateOfBirth = new(year: 1969, month: 11, day: 23)
},
new(20000M)
{
FirstName = "Charlie",
LastName = "Cox",
DateOfBirth = new(year: 1984, month: 5, day: 4),
Children = new()
{
new(0M)
{
FirstName = "Sally",
LastName = "Cox",
DateOfBirth = new(year: 2012, month: 7, day: 12)
}
}
}
};
// create object that will format a List of Persons as XML
XmlSerializer xs = new(type: people.GetType());
// create a file to write to
string path = Combine(CurrentDirectory, "people.xml");
using (FileStream stream = File.Create(path))
{
// serialize the object graph to the stream
xs.Serialize(stream, people);
}
WriteLine("Written {0:N0} bytes of XML to {1}",
arg0: new FileInfo(path).Length,
arg1: path);
WriteLine();
// Display the serialized object graph
WriteLine(File.ReadAllText(path));
WriteLine();
WriteLine("* Deserializing XML files");
using (FileStream xmlLoad = File.Open(path, FileMode.Open))
{
// deserialize and cast the object graph into a List of Person
List<Person>? loadedPeople =
xs.Deserialize(xmlLoad) as List<Person>;
if (loadedPeople is not null)
{
foreach (Person p in loadedPeople)
{
WriteLine("{0} has {1} children.",
p.LastName, p.Children?.Count ?? 0);
}
}
}
// create a file to write to
string jsonPath = Combine(CurrentDirectory, "people.json");
using (StreamWriter jsonStream = File.CreateText(jsonPath))
{
// create an object that will format as JSON
Newtonsoft.Json.JsonSerializer jss = new();
// serialize the object graph into a string
jss.Serialize(jsonStream, people);
}
WriteLine();
WriteLine("Written {0:N0} bytes of JSON to: {1}",
arg0: new FileInfo(jsonPath).Length,
arg1: jsonPath);
// Display the serialized object graph
WriteLine(File.ReadAllText(jsonPath));
WriteLine();
WriteLine("* Deserializing JSON files");
using (FileStream jsonLoad = File.Open(jsonPath, FileMode.Open))
{
// deserialize object graph into a List of Person
List<Person>? loadedPeople =
await NewJson.DeserializeAsync(utf8Json: jsonLoad,
returnType: typeof(List<Person>)) as List<Person>;
if (loadedPeople is not null)
{
foreach (Person p in loadedPeople)
{
WriteLine("{0} has {1} children.",
p.LastName, p.Children?.Count ?? 0);
}
}
}

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,78 @@
using System.IO.Compression; // BrotliStream, GZipStream, CompressionMode
using System.Xml; // XmlWriter, XmlReader
using static System.Environment; // CurrentDirectory
using static System.IO.Path; // Combine
partial class Program
{
static void Compress(string algorithm = "gzip")
{
// define a file path using algorithm as file extension
string filePath = Combine(
CurrentDirectory, $"streams.{algorithm}");
FileStream file = File.Create(filePath);
Stream compressor;
if (algorithm == "gzip")
{
compressor = new GZipStream(file, CompressionMode.Compress);
}
else
{
compressor = new BrotliStream(file, CompressionMode.Compress);
}
using (compressor)
{
using (XmlWriter xml = XmlWriter.Create(compressor))
{
xml.WriteStartDocument();
xml.WriteStartElement("callsigns");
foreach (string item in Viper.Callsigns)
{
xml.WriteElementString("callsign", item);
}
}
} // also closes the underlying stream
// output all the contents of the compressed file
WriteLine("{0} contains {1:N0} bytes.",
filePath, new FileInfo(filePath).Length);
WriteLine($"The compressed contents:");
WriteLine(File.ReadAllText(filePath));
// read a compressed file
WriteLine("Reading the compressed XML file:");
file = File.Open(filePath, FileMode.Open);
Stream decompressor;
if (algorithm == "gzip")
{
decompressor = new GZipStream(
file, CompressionMode.Decompress);
}
else
{
decompressor = new BrotliStream(
file, CompressionMode.Decompress);
}
using (decompressor)
{
using (XmlReader reader = XmlReader.Create(decompressor))
{
while (reader.Read())
{
// check if we are on an element node named callsign
if ((reader.NodeType == XmlNodeType.Element)
&& (reader.Name == "callsign"))
{
reader.Read(); // move to the text inside element
WriteLine($"{reader.Value}"); // read its value
}
}
}
}
}
}

View file

@ -0,0 +1,12 @@
partial class Program
{
static void SectionTitle(string title)
{
ConsoleColor previousColor = ForegroundColor;
ForegroundColor = ConsoleColor.Yellow;
WriteLine("*");
WriteLine($"* {title}");
WriteLine("*");
ForegroundColor = previousColor;
}
}

View file

@ -0,0 +1,94 @@
using System.Xml;
using static System.Environment;
using static System.IO.Path;
SectionTitle("Writing to text streams");
// define a file to write to
string textFile = Combine(CurrentDirectory, "streams.txt");
// create a text file and return a helper writer
StreamWriter text = File.CreateText(textFile);
// enumerate the strings, writing each one
// to the stream on a separate line
foreach (string item in Viper.Callsigns)
{
text.WriteLine(item);
}
text.Close(); // release resources
// output the contents of the file
WriteLine("{0} contains {1:N0} bytes.",
arg0: textFile,
arg1: new FileInfo(textFile).Length);
WriteLine(File.ReadAllText(textFile));
SectionTitle("Writing to XML streams");
// define a file path to write to
string xmlFile = Combine(CurrentDirectory, "streams.xml");
// declare variables for the filestream and XML writer
FileStream? xmlFileStream = null;
XmlWriter? xml = null;
try
{
// create a file stream
xmlFileStream = File.Create(xmlFile);
// wrap the file stream in an XML writer helper
// and automatically indent nested elements
xml = XmlWriter.Create(xmlFileStream,
new XmlWriterSettings { Indent = true });
// write the XML declaration
xml.WriteStartDocument();
// write a root element
xml.WriteStartElement("callsigns");
// enumerate the strings writing each one to the stream
foreach (string item in Viper.Callsigns)
{
xml.WriteElementString("callsign", item);
}
// write the close root element
xml.WriteEndElement();
// close helper and stream
xml.Close();
xmlFileStream.Close();
}
catch (Exception ex)
{
// if the path doesn't exist the exception will be caught
WriteLine($"{ex.GetType()} says {ex.Message}");
}
finally
{
if (xml != null)
{
xml.Dispose();
WriteLine("The XML writer's unmanaged resources have been disposed.");
if (xmlFileStream != null)
{
xmlFileStream.Dispose();
WriteLine("The file stream's unmanaged resources have been disposed.");
}
}
}
// output all the contents of the file
WriteLine("{0} contains {1:N0} bytes.",
arg0: xmlFile,
arg1: new FileInfo(xmlFile).Length);
WriteLine(File.ReadAllText(xmlFile));
SectionTitle("Compressing streams");
Compress(algorithm: "gzip");
Compress(algorithm: "brotli");

View file

@ -0,0 +1,9 @@
static class Viper
{
// define an array of Viper pilot call signs
public static string[] Callsigns = new[]
{
"Husker", "Starbuck", "Apollo", "Boomer",
"Bulldog", "Athena", "Helo", "Racetrack"
};
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
namespace Packt.Shared;
public class Circle : Shape
{
public override double Area
{
get
{
return Math.PI * Radius * Radius;
}
}
public double Radius { get; set; }
}

View file

@ -0,0 +1,50 @@
using Packt.Shared; // Circle, Rectangle, Shape
using System.Xml.Serialization; // XmlSerializer
using static System.Environment;
using static System.IO.Path;
// create a file path to write to
string path = Combine(CurrentDirectory, "shapes.xml");
// create a list of Shape objects to serialize
List<Shape> listOfShapes = new()
{
new Circle { Colour = "Red", Radius = 2.5 },
new Rectangle { Colour = "Blue", Height = 20.0, Width = 10.0 },
new Circle { Colour = "Green", Radius = 8 },
new Circle { Colour = "Purple", Radius = 12.3 },
new Rectangle { Colour = "Blue", Height = 45.0, Width = 18.0 }
};
// create an object that knows how to serialize and deserialize
// a list of Shape objects
XmlSerializer serializerXml = new(listOfShapes.GetType());
WriteLine("Saving shapes to XML file:");
using (FileStream fileXml = File.Create(path))
{
serializerXml.Serialize(fileXml, listOfShapes);
}
WriteLine("Loading shapes from XML file:");
List<Shape>? loadedShapesXml = null;
using (FileStream fileXml = File.Open(path, FileMode.Open))
{
loadedShapesXml =
serializerXml.Deserialize(fileXml) as List<Shape>;
}
if (loadedShapesXml == null)
{
WriteLine($"{nameof(loadedShapesXml)} is empty.");
}
else
{
foreach (Shape item in loadedShapesXml)
{
WriteLine($"{item.GetType().Name} is {item.Colour} and has an area of {item.Area:N2}");
}
}

View file

@ -0,0 +1,15 @@
namespace Packt.Shared;
public class Rectangle : Shape
{
public override double Area
{
get
{
return Height * Width;
}
}
public double Height { get; set; }
public double Width { get; set; }
}

View file

@ -0,0 +1,11 @@
using System.Xml.Serialization;
namespace Packt.Shared;
[XmlInclude(typeof(Circle))]
[XmlInclude(typeof(Rectangle))]
public abstract class Shape
{
public string? Colour { get; set; }
public abstract double Area { get; }
}

View file

@ -0,0 +1,22 @@
{
"folders": [
{
"path": "WorkingWithFileSystems"
},
{
"path": "WorkingWithStreams"
},
{
"path": "WorkingWithEncodings"
},
{
"path": "WorkingWithSerialization"
},
{
"path": "WorkingWithJson"
},
{
"path": "Ch09Ex02SerializingShapes"
}
]
}

View file

@ -0,0 +1,51 @@
using Packt.Shared;
using System.Text;
WriteLine("Encodings");
WriteLine("[1] ASCII");
WriteLine("[2] UTF-7");
WriteLine("[3] UTF-8");
WriteLine("[4] UTF-16 (Unicode)");
WriteLine("[5] UTF-32");
WriteLine("[6] Latin1");
WriteLine("[any other key] Default encoding");
WriteLine();
// choose an encoding
Write("Press a number to choose an encoding.");
ConsoleKey number = ReadKey(intercept: true).Key;
WriteLine(); WriteLine();
Encoding encoder = number switch
{
ConsoleKey.D1 or ConsoleKey.NumPad1 => Encoding.ASCII,
ConsoleKey.D2 or ConsoleKey.NumPad2 => Encoding.UTF7,
ConsoleKey.D3 or ConsoleKey.NumPad3 => Encoding.UTF8,
ConsoleKey.D4 or ConsoleKey.NumPad4 => Encoding.Unicode,
ConsoleKey.D5 or ConsoleKey.NumPad5 => Encoding.UTF32,
ConsoleKey.D6 or ConsoleKey.NumPad6 => Encoding.Latin1,
_ => Encoding.Default
};
// define a string to encode
string message = "Café £4.39";
WriteLine($"Text to encode: {message} Characters: {message.Length}");
// encode the string into a byte array
byte[] encoded = encoder.GetBytes(message);
// check how many bytes the encoding needed
WriteLine("{0} used {1:N0} bytes.",
encoder.GetType().Name, encoded.Length);
WriteLine();
// enumerate each byte
WriteLine($"BYTE | HEX | CHAR");
foreach (byte b in encoded)
{
WriteLine($"{b,4} | {b.ToString("X"),3} | {(char)b,4}");
}
// decode the byte array back into a string and display it
string decoded = encoder.GetString(encoded);
WriteLine(decoded);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
partial class Program
{
static void SectionTitle(string title)
{
ConsoleColor previousColor = ForegroundColor;
ForegroundColor = ConsoleColor.Yellow;
WriteLine("*");
WriteLine($"* {title}");
WriteLine("*");
ForegroundColor = previousColor;
}
}

View file

@ -0,0 +1,132 @@
using static System.IO.Directory;
using static System.IO.Path;
using static System.Environment;
SectionTitle("Handling cross-platform environments and filesystems");
WriteLine("{0,-33} {1}", arg0: "Path.PathSeparator",
arg1: PathSeparator);
WriteLine("{0,-33} {1}", arg0: "Path.DirectorySeparatorChar",
arg1: DirectorySeparatorChar);
WriteLine("{0,-33} {1}", arg0: "Directory.GetCurrentDirectory()",
arg1: GetCurrentDirectory());
WriteLine("{0,-33} {1}", arg0: "Environment.CurrentDirectory",
arg1: CurrentDirectory);
WriteLine("{0,-33} {1}", arg0: "Environment.SystemDirectory",
arg1: SystemDirectory);
WriteLine("{0,-33} {1}", arg0: "Path.GetTempPath()",
arg1: GetTempPath());
WriteLine("GetFolderPath(SpecialFolder");
WriteLine("{0,-33} {1}", arg0: " .System)",
arg1: GetFolderPath(SpecialFolder.System));
WriteLine("{0,-33} {1}", arg0: " .ApplicationData)",
arg1: GetFolderPath(SpecialFolder.ApplicationData));
WriteLine("{0,-33} {1}", arg0: " .MyDocuments)",
arg1: GetFolderPath(SpecialFolder.MyDocuments));
WriteLine("{0,-33} {1}", arg0: " .Personal)",
arg1: GetFolderPath(SpecialFolder.Personal));
SectionTitle("Managing drives");
WriteLine("{0,-30} | {1,-10} | {2,-7} | {3,18} | {4,18}",
"NAME", "TYPE", "FORMAT", "SIZE (BYTES)", "FREE SPACE");
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
if (drive.IsReady)
{
WriteLine(
"{0,-30} | {1,-10} | {2,-7} | {3,18:N0} | {4,18:N0}",
drive.Name, drive.DriveType, drive.DriveFormat,
drive.TotalSize, drive.AvailableFreeSpace);
}
else
{
WriteLine("{0,-30} | {1,-10}", drive.Name, drive.DriveType);
}
}
SectionTitle("Managing directories");
// define a directory path for a new folder
// starting in the user's folder
string newFolder = Combine(
GetFolderPath(SpecialFolder.Personal), "NewFolder");
WriteLine($"Working with: {newFolder}");
// check if it exists
WriteLine($"Does it exist? {Exists(newFolder)}");
// create directory
WriteLine("Creating it...");
CreateDirectory(newFolder);
WriteLine($"Does it exist? {Exists(newFolder)}");
Write("Confirm the directory exists, and then press ENTER: ");
ReadLine();
// delete directory
WriteLine("Deleting it...");
Delete(newFolder, recursive: true);
WriteLine($"Does it exist? {Exists(newFolder)}");
SectionTitle("Managing files");
// define a directory path to output files
// starting in the user's folder
string dir = Combine(
GetFolderPath(SpecialFolder.Personal), "OutputFiles");
CreateDirectory(dir);
// define file paths
string textFile = Combine(dir, "Dummy.txt");
string backupFile = Combine(dir, "Dummy.bak");
WriteLine($"Working with: {textFile}");
// check if a file exists
WriteLine($"Does it exist? {File.Exists(textFile)}");
// create a new text file and write a line to it
StreamWriter textWriter = File.CreateText(textFile);
textWriter.WriteLine("Hello, C#!");
textWriter.Close(); // close file and release resources
WriteLine($"Does it exist? {File.Exists(textFile)}");
// copy the file, and overwrite if it already exists
File.Copy(sourceFileName: textFile,
destFileName: backupFile, overwrite: true);
WriteLine(
$"Does {backupFile} exist? {File.Exists(backupFile)}");
Write("Confirm the files exist, and then press ENTER: ");
ReadLine();
// delete file
File.Delete(textFile);
WriteLine($"Does it exist? {File.Exists(textFile)}");
// read from the text file backup
WriteLine($"Reading contents of {backupFile}:");
StreamReader textReader = File.OpenText(backupFile);
WriteLine(textReader.ReadToEnd());
textReader.Close();
SectionTitle("Managing paths");
WriteLine($"Folder Name: {GetDirectoryName(textFile)}");
WriteLine($"File Name: {GetFileName(textFile)}");
WriteLine("File Name without Extension: {0}",
GetFileNameWithoutExtension(textFile));
WriteLine($"File Extension: {GetExtension(textFile)}");
WriteLine($"Random File Name: {GetRandomFileName()}");
WriteLine($"Temporary File Name: {GetTempFileName()}");
SectionTitle("Getting file information ");
FileInfo info = new(backupFile);
WriteLine($"{backupFile}:");
WriteLine($"Contains {info.Length} bytes");
WriteLine($"Last accessed {info.LastAccessTime}");
WriteLine($"Has readonly set to {info.IsReadOnly}");

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,23 @@
using System.Text.Json.Serialization; // [JsonInclude]
public class Book
{
// constructor to set non-nullable property
public Book(string title)
{
Title = title;
}
// properties
public string Title { get; set; }
public string? Author { get; set; }
// fields
[JsonInclude] // include this field
public DateTime PublishDate;
[JsonInclude] // include this field
public DateTimeOffset Created;
public ushort Pages;
}

View file

@ -0,0 +1,39 @@
using System.Text.Json; // JsonSerializer
using static System.Environment;
using static System.IO.Path;
Book mybook = new(title:
"C# 11 and .NET 7 - Modern Cross-platform Development")
{
Author = "Mark J Price",
PublishDate = new(year: 2022, month: 11, day: 8),
Pages = 823,
Created = DateTimeOffset.UtcNow,
};
JsonSerializerOptions options = new()
{
/*
IncludeFields = true, // includes all fields
PropertyNameCaseInsensitive = true,
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
*/
};
string filePath = Combine(CurrentDirectory, "mybook.json");
using (Stream fileStream = File.Create(filePath))
{
JsonSerializer.Serialize<Book>(
utf8Json: fileStream, value: mybook, options);
}
WriteLine("Written {0:N0} bytes of JSON to {1}",
arg0: new FileInfo(filePath).Length,
arg1: filePath);
WriteLine();
// Display the serialized object graph
WriteLine(File.ReadAllText(filePath));

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,26 @@
using System.Xml.Serialization; // [XmlAttribute]
namespace Packt.Shared;
public class Person
{
public Person() { }
public Person(decimal initialSalary)
{
Salary = initialSalary;
}
[XmlAttribute("fname")]
public string? FirstName { get; set; }
[XmlAttribute("lname")]
public string? LastName { get; set; }
[XmlAttribute("dob")]
public DateTime DateOfBirth { get; set; }
public HashSet<Person>? Children { get; set; }
protected decimal Salary { get; set; }
}

View file

@ -0,0 +1,117 @@
using System.Xml.Serialization; // XmlSerializer
using Packt.Shared; // Person
using NewJson = System.Text.Json.JsonSerializer;
using static System.Environment;
using static System.IO.Path;
// create an object graph
List<Person> people = new()
{
new(30000M)
{
FirstName = "Alice",
LastName = "Smith",
DateOfBirth = new(year: 1974, month: 3, day: 14)
},
new(40000M)
{
FirstName = "Bob",
LastName = "Jones",
DateOfBirth = new(year: 1969, month: 11, day: 23)
},
new(20000M)
{
FirstName = "Charlie",
LastName = "Cox",
DateOfBirth = new(year: 1984, month: 5, day: 4),
Children = new()
{
new(0M)
{
FirstName = "Sally",
LastName = "Cox",
DateOfBirth = new(year: 2012, month: 7, day: 12)
}
}
}
};
// create object that will format a List of Persons as XML
XmlSerializer xs = new(type: people.GetType());
// create a file to write to
string path = Combine(CurrentDirectory, "people.xml");
using (FileStream stream = File.Create(path))
{
// serialize the object graph to the stream
xs.Serialize(stream, people);
}
WriteLine("Written {0:N0} bytes of XML to {1}",
arg0: new FileInfo(path).Length,
arg1: path);
WriteLine();
// Display the serialized object graph
WriteLine(File.ReadAllText(path));
WriteLine();
WriteLine("* Deserializing XML files");
using (FileStream xmlLoad = File.Open(path, FileMode.Open))
{
// deserialize and cast the object graph into a List of Person
List<Person>? loadedPeople =
xs.Deserialize(xmlLoad) as List<Person>;
if (loadedPeople is not null)
{
foreach (Person p in loadedPeople)
{
WriteLine("{0} has {1} children.",
p.LastName, p.Children?.Count ?? 0);
}
}
}
// create a file to write to
string jsonPath = Combine(CurrentDirectory, "people.json");
using (StreamWriter jsonStream = File.CreateText(jsonPath))
{
// create an object that will format as JSON
Newtonsoft.Json.JsonSerializer jss = new();
// serialize the object graph into a string
jss.Serialize(jsonStream, people);
}
WriteLine();
WriteLine("Written {0:N0} bytes of JSON to: {1}",
arg0: new FileInfo(jsonPath).Length,
arg1: jsonPath);
// Display the serialized object graph
WriteLine(File.ReadAllText(jsonPath));
WriteLine();
WriteLine("* Deserializing JSON files");
using (FileStream jsonLoad = File.Open(jsonPath, FileMode.Open))
{
// deserialize object graph into a List of Person
List<Person>? loadedPeople =
await NewJson.DeserializeAsync(utf8Json: jsonLoad,
returnType: typeof(List<Person>)) as List<Person>;
if (loadedPeople is not null)
{
foreach (Person p in loadedPeople)
{
WriteLine("{0} has {1} children.",
p.LastName, p.Children?.Count ?? 0);
}
}
}

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,78 @@
using System.IO.Compression; // BrotliStream, GZipStream, CompressionMode
using System.Xml; // XmlWriter, XmlReader
using static System.Environment; // CurrentDirectory
using static System.IO.Path; // Combine
partial class Program
{
static void Compress(string algorithm = "gzip")
{
// define a file path using algorithm as file extension
string filePath = Combine(
CurrentDirectory, $"streams.{algorithm}");
FileStream file = File.Create(filePath);
Stream compressor;
if (algorithm == "gzip")
{
compressor = new GZipStream(file, CompressionMode.Compress);
}
else
{
compressor = new BrotliStream(file, CompressionMode.Compress);
}
using (compressor)
{
using (XmlWriter xml = XmlWriter.Create(compressor))
{
xml.WriteStartDocument();
xml.WriteStartElement("callsigns");
foreach (string item in Viper.Callsigns)
{
xml.WriteElementString("callsign", item);
}
}
} // also closes the underlying stream
// output all the contents of the compressed file
WriteLine("{0} contains {1:N0} bytes.",
filePath, new FileInfo(filePath).Length);
WriteLine($"The compressed contents:");
WriteLine(File.ReadAllText(filePath));
// read a compressed file
WriteLine("Reading the compressed XML file:");
file = File.Open(filePath, FileMode.Open);
Stream decompressor;
if (algorithm == "gzip")
{
decompressor = new GZipStream(
file, CompressionMode.Decompress);
}
else
{
decompressor = new BrotliStream(
file, CompressionMode.Decompress);
}
using (decompressor)
{
using (XmlReader reader = XmlReader.Create(decompressor))
{
while (reader.Read())
{
// check if we are on an element node named callsign
if ((reader.NodeType == XmlNodeType.Element)
&& (reader.Name == "callsign"))
{
reader.Read(); // move to the text inside element
WriteLine($"{reader.Value}"); // read its value
}
}
}
}
}
}

View file

@ -0,0 +1,12 @@
partial class Program
{
static void SectionTitle(string title)
{
ConsoleColor previousColor = ForegroundColor;
ForegroundColor = ConsoleColor.Yellow;
WriteLine("*");
WriteLine($"* {title}");
WriteLine("*");
ForegroundColor = previousColor;
}
}

View file

@ -0,0 +1,94 @@
using System.Xml;
using static System.Environment;
using static System.IO.Path;
SectionTitle("Writing to text streams");
// define a file to write to
string textFile = Combine(CurrentDirectory, "streams.txt");
// create a text file and return a helper writer
StreamWriter text = File.CreateText(textFile);
// enumerate the strings, writing each one
// to the stream on a separate line
foreach (string item in Viper.Callsigns)
{
text.WriteLine(item);
}
text.Close(); // release resources
// output the contents of the file
WriteLine("{0} contains {1:N0} bytes.",
arg0: textFile,
arg1: new FileInfo(textFile).Length);
WriteLine(File.ReadAllText(textFile));
SectionTitle("Writing to XML streams");
// define a file path to write to
string xmlFile = Combine(CurrentDirectory, "streams.xml");
// declare variables for the filestream and XML writer
FileStream? xmlFileStream = null;
XmlWriter? xml = null;
try
{
// create a file stream
xmlFileStream = File.Create(xmlFile);
// wrap the file stream in an XML writer helper
// and automatically indent nested elements
xml = XmlWriter.Create(xmlFileStream,
new XmlWriterSettings { Indent = true });
// write the XML declaration
xml.WriteStartDocument();
// write a root element
xml.WriteStartElement("callsigns");
// enumerate the strings writing each one to the stream
foreach (string item in Viper.Callsigns)
{
xml.WriteElementString("callsign", item);
}
// write the close root element
xml.WriteEndElement();
// close helper and stream
xml.Close();
xmlFileStream.Close();
}
catch (Exception ex)
{
// if the path doesn't exist the exception will be caught
WriteLine($"{ex.GetType()} says {ex.Message}");
}
finally
{
if (xml != null)
{
xml.Dispose();
WriteLine("The XML writer's unmanaged resources have been disposed.");
if (xmlFileStream != null)
{
xmlFileStream.Dispose();
WriteLine("The file stream's unmanaged resources have been disposed.");
}
}
}
// output all the contents of the file
WriteLine("{0} contains {1:N0} bytes.",
arg0: xmlFile,
arg1: new FileInfo(xmlFile).Length);
WriteLine(File.ReadAllText(xmlFile));
SectionTitle("Compressing streams");
Compress(algorithm: "gzip");
Compress(algorithm: "brotli");

View file

@ -0,0 +1,9 @@
static class Viper
{
// define an array of Viper pilot call signs
public static string[] Callsigns = new[]
{
"Husker", "Starbuck", "Apollo", "Boomer",
"Bulldog", "Athena", "Helo", "Racetrack"
};
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>