From 3d241b215473e4f7258461b0ade8bac9195ca751 Mon Sep 17 00:00:00 2001 From: Mark J Price Date: Fri, 4 Mar 2022 08:34:29 +0000 Subject: [PATCH] Initial commit --- .../Ch09Ex02SerializingShapes.csproj | 14 ++ .../Ch09Ex02SerializingShapes/Circle.cs | 14 ++ .../Ch09Ex02SerializingShapes/Program.cs | 50 +++++++ .../Ch09Ex02SerializingShapes/Rectangle.cs | 15 ++ .../Ch09Ex02SerializingShapes/Shape.cs | 11 ++ vs4win/Chapter09/Chapter09.sln | 55 ++++++++ .../Chapter09/WorkingWithEncodings/Program.cs | 51 +++++++ .../WorkingWithEncodings.csproj | 14 ++ .../WorkingWithFileSystems/Program.Helpers.cs | 12 ++ .../WorkingWithFileSystems/Program.cs | 132 ++++++++++++++++++ .../WorkingWithFileSystems.csproj | 14 ++ vs4win/Chapter09/WorkingWithJson/Book.cs | 23 +++ vs4win/Chapter09/WorkingWithJson/Program.cs | 39 ++++++ .../WorkingWithJson/WorkingWithJson.csproj | 14 ++ .../WorkingWithSerialization/Person.cs | 26 ++++ .../WorkingWithSerialization/Program.cs | 117 ++++++++++++++++ .../WorkingWithSerialization.csproj | 18 +++ .../WorkingWithStreams/Program.Compress.cs | 78 +++++++++++ .../WorkingWithStreams/Program.Helpers.cs | 12 ++ .../Chapter09/WorkingWithStreams/Program.cs | 94 +++++++++++++ vs4win/Chapter09/WorkingWithStreams/Viper.cs | 9 ++ .../WorkingWithStreams.csproj | 14 ++ .../Ch09Ex02SerializingShapes.csproj | 14 ++ .../Ch09Ex02SerializingShapes/Circle.cs | 14 ++ .../Ch09Ex02SerializingShapes/Program.cs | 50 +++++++ .../Ch09Ex02SerializingShapes/Rectangle.cs | 15 ++ .../Ch09Ex02SerializingShapes/Shape.cs | 11 ++ vscode/Chapter09/Chapter09.code-workspace | 22 +++ .../Chapter09/WorkingWithEncodings/Program.cs | 51 +++++++ .../WorkingWithEncodings.csproj | 14 ++ .../WorkingWithFileSystems/Program.Helpers.cs | 12 ++ .../WorkingWithFileSystems/Program.cs | 132 ++++++++++++++++++ .../WorkingWithFileSystems.csproj | 14 ++ vscode/Chapter09/WorkingWithJson/Book.cs | 23 +++ vscode/Chapter09/WorkingWithJson/Program.cs | 39 ++++++ .../WorkingWithJson/WorkingWithJson.csproj | 14 ++ .../WorkingWithSerialization/Person.cs | 26 ++++ .../WorkingWithSerialization/Program.cs | 117 ++++++++++++++++ .../WorkingWithSerialization.csproj | 18 +++ .../WorkingWithStreams/Program.Compress.cs | 78 +++++++++++ .../WorkingWithStreams/Program.Helpers.cs | 12 ++ .../Chapter09/WorkingWithStreams/Program.cs | 94 +++++++++++++ vscode/Chapter09/WorkingWithStreams/Viper.cs | 9 ++ .../WorkingWithStreams.csproj | 14 ++ 44 files changed, 1619 insertions(+) create mode 100644 vs4win/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj create mode 100644 vs4win/Chapter09/Ch09Ex02SerializingShapes/Circle.cs create mode 100644 vs4win/Chapter09/Ch09Ex02SerializingShapes/Program.cs create mode 100644 vs4win/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs create mode 100644 vs4win/Chapter09/Ch09Ex02SerializingShapes/Shape.cs create mode 100644 vs4win/Chapter09/Chapter09.sln create mode 100644 vs4win/Chapter09/WorkingWithEncodings/Program.cs create mode 100644 vs4win/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj create mode 100644 vs4win/Chapter09/WorkingWithFileSystems/Program.Helpers.cs create mode 100644 vs4win/Chapter09/WorkingWithFileSystems/Program.cs create mode 100644 vs4win/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj create mode 100644 vs4win/Chapter09/WorkingWithJson/Book.cs create mode 100644 vs4win/Chapter09/WorkingWithJson/Program.cs create mode 100644 vs4win/Chapter09/WorkingWithJson/WorkingWithJson.csproj create mode 100644 vs4win/Chapter09/WorkingWithSerialization/Person.cs create mode 100644 vs4win/Chapter09/WorkingWithSerialization/Program.cs create mode 100644 vs4win/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj create mode 100644 vs4win/Chapter09/WorkingWithStreams/Program.Compress.cs create mode 100644 vs4win/Chapter09/WorkingWithStreams/Program.Helpers.cs create mode 100644 vs4win/Chapter09/WorkingWithStreams/Program.cs create mode 100644 vs4win/Chapter09/WorkingWithStreams/Viper.cs create mode 100644 vs4win/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj create mode 100644 vscode/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj create mode 100644 vscode/Chapter09/Ch09Ex02SerializingShapes/Circle.cs create mode 100644 vscode/Chapter09/Ch09Ex02SerializingShapes/Program.cs create mode 100644 vscode/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs create mode 100644 vscode/Chapter09/Ch09Ex02SerializingShapes/Shape.cs create mode 100644 vscode/Chapter09/Chapter09.code-workspace create mode 100644 vscode/Chapter09/WorkingWithEncodings/Program.cs create mode 100644 vscode/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj create mode 100644 vscode/Chapter09/WorkingWithFileSystems/Program.Helpers.cs create mode 100644 vscode/Chapter09/WorkingWithFileSystems/Program.cs create mode 100644 vscode/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj create mode 100644 vscode/Chapter09/WorkingWithJson/Book.cs create mode 100644 vscode/Chapter09/WorkingWithJson/Program.cs create mode 100644 vscode/Chapter09/WorkingWithJson/WorkingWithJson.csproj create mode 100644 vscode/Chapter09/WorkingWithSerialization/Person.cs create mode 100644 vscode/Chapter09/WorkingWithSerialization/Program.cs create mode 100644 vscode/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj create mode 100644 vscode/Chapter09/WorkingWithStreams/Program.Compress.cs create mode 100644 vscode/Chapter09/WorkingWithStreams/Program.Helpers.cs create mode 100644 vscode/Chapter09/WorkingWithStreams/Program.cs create mode 100644 vscode/Chapter09/WorkingWithStreams/Viper.cs create mode 100644 vscode/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj diff --git a/vs4win/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vs4win/Chapter09/Ch09Ex02SerializingShapes/Circle.cs b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Circle.cs new file mode 100644 index 0000000..92e01ae --- /dev/null +++ b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Circle.cs @@ -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; } +} diff --git a/vs4win/Chapter09/Ch09Ex02SerializingShapes/Program.cs b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Program.cs new file mode 100644 index 0000000..aa808b1 --- /dev/null +++ b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Program.cs @@ -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 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? loadedShapesXml = null; + +using (FileStream fileXml = File.Open(path, FileMode.Open)) +{ + loadedShapesXml = + serializerXml.Deserialize(fileXml) as List; +} + +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}"); + } +} diff --git a/vs4win/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs new file mode 100644 index 0000000..c525738 --- /dev/null +++ b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs @@ -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; } +} diff --git a/vs4win/Chapter09/Ch09Ex02SerializingShapes/Shape.cs b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Shape.cs new file mode 100644 index 0000000..5166775 --- /dev/null +++ b/vs4win/Chapter09/Ch09Ex02SerializingShapes/Shape.cs @@ -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; } +} diff --git a/vs4win/Chapter09/Chapter09.sln b/vs4win/Chapter09/Chapter09.sln new file mode 100644 index 0000000..f39aaac --- /dev/null +++ b/vs4win/Chapter09/Chapter09.sln @@ -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 diff --git a/vs4win/Chapter09/WorkingWithEncodings/Program.cs b/vs4win/Chapter09/WorkingWithEncodings/Program.cs new file mode 100644 index 0000000..02ef0ec --- /dev/null +++ b/vs4win/Chapter09/WorkingWithEncodings/Program.cs @@ -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); diff --git a/vs4win/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj b/vs4win/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vs4win/Chapter09/WorkingWithFileSystems/Program.Helpers.cs b/vs4win/Chapter09/WorkingWithFileSystems/Program.Helpers.cs new file mode 100644 index 0000000..b3ae32b --- /dev/null +++ b/vs4win/Chapter09/WorkingWithFileSystems/Program.Helpers.cs @@ -0,0 +1,12 @@ +partial class Program +{ + static void SectionTitle(string title) + { + ConsoleColor previousColor = ForegroundColor; + ForegroundColor = ConsoleColor.Yellow; + WriteLine("*"); + WriteLine($"* {title}"); + WriteLine("*"); + ForegroundColor = previousColor; + } +} diff --git a/vs4win/Chapter09/WorkingWithFileSystems/Program.cs b/vs4win/Chapter09/WorkingWithFileSystems/Program.cs new file mode 100644 index 0000000..cf4213e --- /dev/null +++ b/vs4win/Chapter09/WorkingWithFileSystems/Program.cs @@ -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}"); diff --git a/vs4win/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj b/vs4win/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vs4win/Chapter09/WorkingWithJson/Book.cs b/vs4win/Chapter09/WorkingWithJson/Book.cs new file mode 100644 index 0000000..5932324 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithJson/Book.cs @@ -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; +} diff --git a/vs4win/Chapter09/WorkingWithJson/Program.cs b/vs4win/Chapter09/WorkingWithJson/Program.cs new file mode 100644 index 0000000..eb6c8bd --- /dev/null +++ b/vs4win/Chapter09/WorkingWithJson/Program.cs @@ -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( + 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)); diff --git a/vs4win/Chapter09/WorkingWithJson/WorkingWithJson.csproj b/vs4win/Chapter09/WorkingWithJson/WorkingWithJson.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithJson/WorkingWithJson.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vs4win/Chapter09/WorkingWithSerialization/Person.cs b/vs4win/Chapter09/WorkingWithSerialization/Person.cs new file mode 100644 index 0000000..286d1c3 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithSerialization/Person.cs @@ -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? Children { get; set; } + + protected decimal Salary { get; set; } +} diff --git a/vs4win/Chapter09/WorkingWithSerialization/Program.cs b/vs4win/Chapter09/WorkingWithSerialization/Program.cs new file mode 100644 index 0000000..4ebf83f --- /dev/null +++ b/vs4win/Chapter09/WorkingWithSerialization/Program.cs @@ -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 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? loadedPeople = + xs.Deserialize(xmlLoad) as List; + + 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? loadedPeople = + await NewJson.DeserializeAsync(utf8Json: jsonLoad, + returnType: typeof(List)) as List; + + if (loadedPeople is not null) + { + foreach (Person p in loadedPeople) + { + WriteLine("{0} has {1} children.", + p.LastName, p.Children?.Count ?? 0); + } + } +} diff --git a/vs4win/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj b/vs4win/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj new file mode 100644 index 0000000..92ae860 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj @@ -0,0 +1,18 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + diff --git a/vs4win/Chapter09/WorkingWithStreams/Program.Compress.cs b/vs4win/Chapter09/WorkingWithStreams/Program.Compress.cs new file mode 100644 index 0000000..cbd9c19 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithStreams/Program.Compress.cs @@ -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 + } + } + } + } + } +} diff --git a/vs4win/Chapter09/WorkingWithStreams/Program.Helpers.cs b/vs4win/Chapter09/WorkingWithStreams/Program.Helpers.cs new file mode 100644 index 0000000..b3ae32b --- /dev/null +++ b/vs4win/Chapter09/WorkingWithStreams/Program.Helpers.cs @@ -0,0 +1,12 @@ +partial class Program +{ + static void SectionTitle(string title) + { + ConsoleColor previousColor = ForegroundColor; + ForegroundColor = ConsoleColor.Yellow; + WriteLine("*"); + WriteLine($"* {title}"); + WriteLine("*"); + ForegroundColor = previousColor; + } +} diff --git a/vs4win/Chapter09/WorkingWithStreams/Program.cs b/vs4win/Chapter09/WorkingWithStreams/Program.cs new file mode 100644 index 0000000..695536f --- /dev/null +++ b/vs4win/Chapter09/WorkingWithStreams/Program.cs @@ -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"); diff --git a/vs4win/Chapter09/WorkingWithStreams/Viper.cs b/vs4win/Chapter09/WorkingWithStreams/Viper.cs new file mode 100644 index 0000000..ff4b5b1 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithStreams/Viper.cs @@ -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" + }; +} diff --git a/vs4win/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj b/vs4win/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vs4win/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vscode/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj b/vscode/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vscode/Chapter09/Ch09Ex02SerializingShapes/Ch09Ex02SerializingShapes.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vscode/Chapter09/Ch09Ex02SerializingShapes/Circle.cs b/vscode/Chapter09/Ch09Ex02SerializingShapes/Circle.cs new file mode 100644 index 0000000..92e01ae --- /dev/null +++ b/vscode/Chapter09/Ch09Ex02SerializingShapes/Circle.cs @@ -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; } +} diff --git a/vscode/Chapter09/Ch09Ex02SerializingShapes/Program.cs b/vscode/Chapter09/Ch09Ex02SerializingShapes/Program.cs new file mode 100644 index 0000000..aa808b1 --- /dev/null +++ b/vscode/Chapter09/Ch09Ex02SerializingShapes/Program.cs @@ -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 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? loadedShapesXml = null; + +using (FileStream fileXml = File.Open(path, FileMode.Open)) +{ + loadedShapesXml = + serializerXml.Deserialize(fileXml) as List; +} + +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}"); + } +} diff --git a/vscode/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs b/vscode/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs new file mode 100644 index 0000000..c525738 --- /dev/null +++ b/vscode/Chapter09/Ch09Ex02SerializingShapes/Rectangle.cs @@ -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; } +} diff --git a/vscode/Chapter09/Ch09Ex02SerializingShapes/Shape.cs b/vscode/Chapter09/Ch09Ex02SerializingShapes/Shape.cs new file mode 100644 index 0000000..5166775 --- /dev/null +++ b/vscode/Chapter09/Ch09Ex02SerializingShapes/Shape.cs @@ -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; } +} diff --git a/vscode/Chapter09/Chapter09.code-workspace b/vscode/Chapter09/Chapter09.code-workspace new file mode 100644 index 0000000..05f31d5 --- /dev/null +++ b/vscode/Chapter09/Chapter09.code-workspace @@ -0,0 +1,22 @@ +{ + "folders": [ + { + "path": "WorkingWithFileSystems" + }, + { + "path": "WorkingWithStreams" + }, + { + "path": "WorkingWithEncodings" + }, + { + "path": "WorkingWithSerialization" + }, + { + "path": "WorkingWithJson" + }, + { + "path": "Ch09Ex02SerializingShapes" + } + ] +} \ No newline at end of file diff --git a/vscode/Chapter09/WorkingWithEncodings/Program.cs b/vscode/Chapter09/WorkingWithEncodings/Program.cs new file mode 100644 index 0000000..02ef0ec --- /dev/null +++ b/vscode/Chapter09/WorkingWithEncodings/Program.cs @@ -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); diff --git a/vscode/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj b/vscode/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vscode/Chapter09/WorkingWithEncodings/WorkingWithEncodings.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vscode/Chapter09/WorkingWithFileSystems/Program.Helpers.cs b/vscode/Chapter09/WorkingWithFileSystems/Program.Helpers.cs new file mode 100644 index 0000000..b3ae32b --- /dev/null +++ b/vscode/Chapter09/WorkingWithFileSystems/Program.Helpers.cs @@ -0,0 +1,12 @@ +partial class Program +{ + static void SectionTitle(string title) + { + ConsoleColor previousColor = ForegroundColor; + ForegroundColor = ConsoleColor.Yellow; + WriteLine("*"); + WriteLine($"* {title}"); + WriteLine("*"); + ForegroundColor = previousColor; + } +} diff --git a/vscode/Chapter09/WorkingWithFileSystems/Program.cs b/vscode/Chapter09/WorkingWithFileSystems/Program.cs new file mode 100644 index 0000000..cf4213e --- /dev/null +++ b/vscode/Chapter09/WorkingWithFileSystems/Program.cs @@ -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}"); diff --git a/vscode/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj b/vscode/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vscode/Chapter09/WorkingWithFileSystems/WorkingWithFileSystems.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vscode/Chapter09/WorkingWithJson/Book.cs b/vscode/Chapter09/WorkingWithJson/Book.cs new file mode 100644 index 0000000..5932324 --- /dev/null +++ b/vscode/Chapter09/WorkingWithJson/Book.cs @@ -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; +} diff --git a/vscode/Chapter09/WorkingWithJson/Program.cs b/vscode/Chapter09/WorkingWithJson/Program.cs new file mode 100644 index 0000000..eb6c8bd --- /dev/null +++ b/vscode/Chapter09/WorkingWithJson/Program.cs @@ -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( + 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)); diff --git a/vscode/Chapter09/WorkingWithJson/WorkingWithJson.csproj b/vscode/Chapter09/WorkingWithJson/WorkingWithJson.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vscode/Chapter09/WorkingWithJson/WorkingWithJson.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/vscode/Chapter09/WorkingWithSerialization/Person.cs b/vscode/Chapter09/WorkingWithSerialization/Person.cs new file mode 100644 index 0000000..286d1c3 --- /dev/null +++ b/vscode/Chapter09/WorkingWithSerialization/Person.cs @@ -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? Children { get; set; } + + protected decimal Salary { get; set; } +} diff --git a/vscode/Chapter09/WorkingWithSerialization/Program.cs b/vscode/Chapter09/WorkingWithSerialization/Program.cs new file mode 100644 index 0000000..4ebf83f --- /dev/null +++ b/vscode/Chapter09/WorkingWithSerialization/Program.cs @@ -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 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? loadedPeople = + xs.Deserialize(xmlLoad) as List; + + 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? loadedPeople = + await NewJson.DeserializeAsync(utf8Json: jsonLoad, + returnType: typeof(List)) as List; + + if (loadedPeople is not null) + { + foreach (Person p in loadedPeople) + { + WriteLine("{0} has {1} children.", + p.LastName, p.Children?.Count ?? 0); + } + } +} diff --git a/vscode/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj b/vscode/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj new file mode 100644 index 0000000..92ae860 --- /dev/null +++ b/vscode/Chapter09/WorkingWithSerialization/WorkingWithSerialization.csproj @@ -0,0 +1,18 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + diff --git a/vscode/Chapter09/WorkingWithStreams/Program.Compress.cs b/vscode/Chapter09/WorkingWithStreams/Program.Compress.cs new file mode 100644 index 0000000..cbd9c19 --- /dev/null +++ b/vscode/Chapter09/WorkingWithStreams/Program.Compress.cs @@ -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 + } + } + } + } + } +} diff --git a/vscode/Chapter09/WorkingWithStreams/Program.Helpers.cs b/vscode/Chapter09/WorkingWithStreams/Program.Helpers.cs new file mode 100644 index 0000000..b3ae32b --- /dev/null +++ b/vscode/Chapter09/WorkingWithStreams/Program.Helpers.cs @@ -0,0 +1,12 @@ +partial class Program +{ + static void SectionTitle(string title) + { + ConsoleColor previousColor = ForegroundColor; + ForegroundColor = ConsoleColor.Yellow; + WriteLine("*"); + WriteLine($"* {title}"); + WriteLine("*"); + ForegroundColor = previousColor; + } +} diff --git a/vscode/Chapter09/WorkingWithStreams/Program.cs b/vscode/Chapter09/WorkingWithStreams/Program.cs new file mode 100644 index 0000000..695536f --- /dev/null +++ b/vscode/Chapter09/WorkingWithStreams/Program.cs @@ -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"); diff --git a/vscode/Chapter09/WorkingWithStreams/Viper.cs b/vscode/Chapter09/WorkingWithStreams/Viper.cs new file mode 100644 index 0000000..ff4b5b1 --- /dev/null +++ b/vscode/Chapter09/WorkingWithStreams/Viper.cs @@ -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" + }; +} diff --git a/vscode/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj b/vscode/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj new file mode 100644 index 0000000..cd63b28 --- /dev/null +++ b/vscode/Chapter09/WorkingWithStreams/WorkingWithStreams.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + +