Skip to content

Commit 9dbaee6

Browse files
author
Manuel Eisenschink
committed
Separated code in library and console test app, upgraded to .NET STD 2.0
Improved code quality, moved to C#11, fixed minor bug
1 parent b88428a commit 9dbaee6

14 files changed

+429
-520
lines changed

TreeIterator/FileSystemTree.cs renamed to TreeIterator.TestApp/FileSystemTree.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
using System;
2-
using System.Runtime.Serialization;
1+
using System.Runtime.Serialization;
32

4-
namespace TreeIterator
3+
namespace TreeIterator.TestApp
54
{
65
///=================================================================================================
76
/// <summary> A file system tree. This class cannot be inherited. </summary>
@@ -13,7 +12,7 @@ namespace TreeIterator
1312
[Serializable]
1413
public sealed class FileSystemTree : Tree<FileSystemTreeBranch>
1514
{
16-
public FileSystemTree() : base(new FileSystemTreeBranch("Root", true))
15+
public FileSystemTree() : base(new("Root", true))
1716
{
1817
}
1918

@@ -38,4 +37,4 @@ public FileSystemTree(FileSystemTreeBranch root) : base(root)
3837
{
3938
}
4039
}
41-
}
40+
}

TreeIterator/FileSystemTreeBranch.cs renamed to TreeIterator.TestApp/FileSystemTreeBranch.cs

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
using System;
2-
using System.IO;
3-
using System.Linq;
4-
using System.Runtime.Serialization;
5-
using System.Security.Permissions;
6-
using System.Text;
1+
using System.Runtime.Serialization;
72
using System.Xml;
83

9-
namespace TreeIterator
4+
namespace TreeIterator.TestApp
105
{
116
///=================================================================================================
127
/// <summary> A file system tree branch. This class cannot be inherited. </summary>
@@ -23,7 +18,7 @@ public sealed class FileSystemTreeBranch : TreeBranch
2318
///
2419
/// <value> The name. </value>
2520
///=================================================================================================
26-
public string Name { get; private set; }
21+
public string Name { get; private set; } = string.Empty;
2722

2823
///=================================================================================================
2924
/// <summary> Gets or sets a value indicating whether this instance is directory. </summary>
@@ -62,13 +57,14 @@ public FileSystemTreeBranch(string name, bool isDirectory)
6257
///=================================================================================================
6358
private FileSystemTreeBranch(SerializationInfo info, StreamingContext context)
6459
{
65-
Name = info.GetString("Name");
60+
Name = info.GetString("Name") ?? string.Empty;
6661
IsDirectory = info.GetBoolean("IsDirectory");
6762
int branchCount = info.GetInt32("Branches");
6863
if (branchCount == 0) return;
6964
for (int i = 0; i < branchCount; i++)
7065
{
71-
FileSystemTreeBranch branch = (FileSystemTreeBranch)info.GetValue("Branch" + i, typeof(FileSystemTreeBranch));
66+
FileSystemTreeBranch branch = (FileSystemTreeBranch?)info.GetValue("Branch" + i, typeof(FileSystemTreeBranch)) ??
67+
throw new SerializationException($"Failed to deserialize tree branch (index {i}).");
7268
AddBranch(branch);
7369
}
7470
}
@@ -103,7 +99,6 @@ public override void Dump(StreamWriter writer, int level)
10399
///
104100
/// <seealso cref="M:TreeIterator.TreeBranch.GetObjectData(SerializationInfo,StreamingContext)"/>
105101
///=================================================================================================
106-
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
107102
public override void GetObjectData(SerializationInfo info, StreamingContext context)
108103
{
109104
info.AddValue("Name", Name);

TreeIterator.TestApp/Program.cs

+321
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
using System.Diagnostics;
2+
using System.Runtime.Serialization.Formatters.Binary;
3+
using TreeIterator;
4+
using TreeIterator.TestApp;
5+
// ReSharper disable RedundantAssignment
6+
#pragma warning disable SYSLIB0011
7+
8+
bool iterate = true;
9+
TreeEnumerationMode enumerationMode = TreeEnumerationMode.DepthFirst;
10+
11+
EnterSelection:
12+
Console.Clear();
13+
Write("Please choose what you want to do:");
14+
Write("1 - Mirror directory in tree, iterate it (timing), serialize " +
15+
"tree binary (legacy + custom), as XML and dump it as text.");
16+
Write("2 - Deserialize from legacy binary file");
17+
Write("3 - Deserialize from custom binary file");
18+
Write("4 - Deserialize from XML");
19+
Write($"5 - Change deserialization iteration on/off [Current: {iterate}]");
20+
Write($"6 - Change enumeration mode Depth/Breadth [Current: {enumerationMode} - Color " +
21+
"Code: " + (enumerationMode == TreeEnumerationMode.DepthFirst ? "Cyan" : "Green") + "]");
22+
Write("7 - Exit");
23+
24+
if (!int.TryParse(Console.ReadLine(), out var selection))
25+
goto EnterSelection;
26+
27+
Stopwatch stopwatch = new();
28+
29+
if (selection == 1)
30+
{
31+
EnterPath:
32+
Write("Enter any directory which should be built as tree (or enter for the test directory [recommended]:");
33+
string? rootDir = Console.ReadLine();
34+
if (string.IsNullOrEmpty(rootDir))
35+
{
36+
rootDir = Path.Combine(Environment.CurrentDirectory, "Test Folder");
37+
}
38+
39+
DirectoryInfo root;
40+
try
41+
{
42+
root = new(rootDir);
43+
if (!root.Exists) throw new();
44+
}
45+
catch
46+
{
47+
Write("Yeah sure thing, but that ain't no valid directory. Once again...", ConsoleColor.Red);
48+
goto EnterPath;
49+
}
50+
51+
string output = Path.Combine(Environment.CurrentDirectory, "fsTree.txt");
52+
Write($"A tree of the file system structure will be built now. " +
53+
$"The output will be placed inside '{output}'.", ConsoleColor.Cyan);
54+
Write("Depending on your directory this might take a while. Don't close the application! Stuff is happening right now.",
55+
ConsoleColor.Yellow);
56+
57+
// Build tree
58+
FileSystemTreeBranch rootBranch = new(root.Name, true);
59+
FileSystemTree tree = new(rootBranch);
60+
61+
BuildTree(root, rootBranch);
62+
63+
Write("The tree is built up. Press key to start iteration. WARNING: No real performance test!", ConsoleColor.Yellow);
64+
Console.ReadLine();
65+
66+
Console.ForegroundColor = ConsoleColor.Magenta;
67+
tree.EnumerationMode = TreeEnumerationMode.BreadthFirst;
68+
69+
// Cold run-through
70+
71+
stopwatch.Start();
72+
foreach (var _ in tree)
73+
{
74+
}
75+
76+
stopwatch.Stop();
77+
Write($"Breadth-first cold run-through: {stopwatch.Elapsed.TotalMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds} s).",
78+
ConsoleColor.Red);
79+
80+
// Warm run-through
81+
stopwatch.Restart();
82+
foreach (var _ in tree)
83+
{
84+
}
85+
86+
stopwatch.Stop();
87+
Write($"Breadth-first warm run-through: {stopwatch.Elapsed.TotalMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds} s).",
88+
ConsoleColor.Red);
89+
90+
// Cold run-through
91+
tree.EnumerationMode = TreeEnumerationMode.DepthFirst;
92+
stopwatch.Restart();
93+
foreach (var _ in tree)
94+
{
95+
}
96+
97+
stopwatch.Stop();
98+
Write($"Depth-first cold run-through: {stopwatch.Elapsed.TotalMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds} s).",
99+
ConsoleColor.Red);
100+
101+
// Warm run-through
102+
stopwatch.Restart();
103+
foreach (var _ in tree)
104+
{
105+
}
106+
107+
stopwatch.Stop();
108+
Write($"Depth-first warm run-through: {stopwatch.Elapsed.TotalMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds} s).",
109+
ConsoleColor.Red);
110+
111+
// Dump
112+
stopwatch.Restart();
113+
tree.Dump(output);
114+
stopwatch.Stop();
115+
116+
Performance("Text dump write down", stopwatch.Elapsed);
117+
118+
// Serialize
119+
BinaryFormatter formatter = new();
120+
using (FileStream fs = new(Path.Combine(Environment.CurrentDirectory, "tree.legacybin"), FileMode.OpenOrCreate))
121+
{
122+
stopwatch.Restart();
123+
formatter.Serialize(fs, tree);
124+
stopwatch.Stop();
125+
}
126+
127+
Performance("Legacy binary write down", stopwatch.Elapsed);
128+
129+
stopwatch.Restart();
130+
tree.WriteXml(Path.Combine(Environment.CurrentDirectory, "tree.xml"));
131+
stopwatch.Stop();
132+
133+
Performance("XML write down", stopwatch.Elapsed);
134+
135+
stopwatch.Restart();
136+
tree.WriteBinary(Path.Combine(Environment.CurrentDirectory, "tree.bin"));
137+
stopwatch.Stop();
138+
139+
Performance("Binary write down", stopwatch.Elapsed);
140+
141+
Console.ReadLine();
142+
Process.Start(Environment.CurrentDirectory);
143+
}
144+
else if (selection == 2)
145+
{
146+
string file = Path.Combine(Environment.CurrentDirectory, "tree.legacybin");
147+
BinaryFormatter formatter = new();
148+
try
149+
{
150+
FileSystemTree fsTree;
151+
using (FileStream fs = new(file, FileMode.Open))
152+
{
153+
// Cold run-through
154+
stopwatch.Start();
155+
fsTree = (FileSystemTree)formatter.Deserialize(fs);
156+
stopwatch.Stop();
157+
158+
Performance("Legacy binary deserialization cold run-through", stopwatch.Elapsed);
159+
160+
// Warm run-through
161+
fs.Seek(0, SeekOrigin.Begin);
162+
stopwatch.Restart();
163+
fsTree = (FileSystemTree)formatter.Deserialize(fs);
164+
stopwatch.Stop();
165+
166+
Performance("Legacy binary deserialization warm run-through", stopwatch.Elapsed);
167+
}
168+
169+
if (iterate)
170+
{
171+
Console.ForegroundColor = enumerationMode == TreeEnumerationMode.DepthFirst
172+
? ConsoleColor.Cyan
173+
: ConsoleColor.Green;
174+
fsTree.EnumerationMode = enumerationMode;
175+
foreach (var branch in fsTree)
176+
{
177+
Console.WriteLine(branch);
178+
}
179+
}
180+
181+
Write(Environment.NewLine);
182+
}
183+
catch (Exception ex)
184+
{
185+
Write("Error parsing legacy binary file:", ConsoleColor.Red);
186+
Write(ex.Message + ex.StackTrace, ConsoleColor.Red);
187+
}
188+
189+
Write(Environment.NewLine);
190+
Console.Read();
191+
}
192+
else if (selection == 3)
193+
{
194+
string file = Path.Combine(Environment.CurrentDirectory, "tree.bin");
195+
try
196+
{
197+
// Cold run-through
198+
stopwatch.Start();
199+
FileSystemTree fsTree = Tree.ParseBinary<FileSystemTree>(file);
200+
stopwatch.Stop();
201+
202+
Performance("Binary deserialization cold run-through", stopwatch.Elapsed);
203+
204+
// Warm run-through
205+
stopwatch.Restart();
206+
fsTree = (FileSystemTree)Tree<FileSystemTreeBranch>.ParseBinary(file);
207+
stopwatch.Stop();
208+
209+
Performance("Binary deserialization warm run-through", stopwatch.Elapsed);
210+
211+
if (iterate)
212+
{
213+
Console.ForegroundColor = enumerationMode == TreeEnumerationMode.DepthFirst
214+
? ConsoleColor.Cyan
215+
: ConsoleColor.Green;
216+
fsTree.EnumerationMode = enumerationMode;
217+
foreach (var branch in fsTree)
218+
{
219+
Console.WriteLine(branch);
220+
}
221+
}
222+
223+
Write(Environment.NewLine);
224+
}
225+
catch (Exception ex)
226+
{
227+
Write("Error parsing binary file:", ConsoleColor.Red);
228+
Write(ex.Message + ex.StackTrace, ConsoleColor.Red);
229+
}
230+
231+
Write(Environment.NewLine);
232+
Console.Read();
233+
}
234+
else if (selection == 4)
235+
{
236+
string file = Path.Combine(Environment.CurrentDirectory, "tree.xml");
237+
try
238+
{
239+
// Cold run-through
240+
stopwatch.Start();
241+
FileSystemTree fsTree = (FileSystemTree)Tree.ParseXml(file);
242+
stopwatch.Stop();
243+
244+
Performance("XML deserialization cold run-through", stopwatch.Elapsed);
245+
246+
// Warm run-through
247+
stopwatch.Restart();
248+
fsTree = (FileSystemTree)Tree.ParseXml(file);
249+
stopwatch.Stop();
250+
251+
Performance("XML deserialization warm run-through", stopwatch.Elapsed);
252+
253+
if (iterate)
254+
{
255+
Console.ForegroundColor = enumerationMode == TreeEnumerationMode.DepthFirst
256+
? ConsoleColor.Cyan
257+
: ConsoleColor.Green;
258+
fsTree.EnumerationMode = enumerationMode;
259+
foreach (var branch in fsTree)
260+
{
261+
Console.WriteLine(branch);
262+
}
263+
}
264+
265+
Write(Environment.NewLine);
266+
}
267+
catch (Exception ex)
268+
{
269+
Write("Error parsing XML file:", ConsoleColor.Red);
270+
Write(ex.Message + ex.StackTrace, ConsoleColor.Red);
271+
}
272+
273+
Write(Environment.NewLine);
274+
Console.Read();
275+
}
276+
else if (selection == 5)
277+
{
278+
iterate = !iterate;
279+
}
280+
else if (selection == 6)
281+
{
282+
enumerationMode = enumerationMode == TreeEnumerationMode.DepthFirst
283+
? TreeEnumerationMode.BreadthFirst
284+
: TreeEnumerationMode.DepthFirst;
285+
}
286+
else if (selection == 7) return;
287+
288+
goto EnterSelection;
289+
290+
291+
static void BuildTree(DirectoryInfo current, FileSystemTreeBranch branch)
292+
{
293+
// Scans the file system structure and builds up the tree
294+
// The try/catch is necessary for system files as these would fire exceptions
295+
try
296+
{
297+
foreach (var file in current.GetFiles())
298+
branch.AddBranch(new FileSystemTreeBranch(file.Name, false));
299+
foreach (var dir in current.GetDirectories())
300+
{
301+
FileSystemTreeBranch next = new(dir.Name, true);
302+
BuildTree(dir, next);
303+
branch.AddBranch(next);
304+
}
305+
}
306+
catch (UnauthorizedAccessException)
307+
{
308+
}
309+
}
310+
311+
static void Write(string message, ConsoleColor color = ConsoleColor.White)
312+
{
313+
Console.ForegroundColor = color;
314+
Console.WriteLine(message);
315+
}
316+
317+
static void Performance(string name, TimeSpan timing)
318+
{
319+
Console.ForegroundColor = ConsoleColor.Magenta;
320+
Console.WriteLine($"[PERFORMANCE] {name}: {timing.TotalMilliseconds} ms ({timing.TotalSeconds} s)");
321+
}

0 commit comments

Comments
 (0)