-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
143 lines (126 loc) · 5.56 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.IO;
using System.Linq;
using System.Threading;
namespace FolderCompare
{
static class Program
{
static void Main(string[] args)
{
if (args.Length < 2 || (args.Length == 3 && args[2] != "/slice") || args.Length > 3)
{
Usage();
}
var slice = args.Length == 3;
var sourceFolder = args[0];
var destinationFolder = args[1];
CheckFolderExists(sourceFolder);
CheckFolderExists(destinationFolder);
int? skip = null, take = null;
if (slice)
{
Console.WriteLine("Counting files to determine current slice");
var count = FileAccess.GetFiles(new CompareStatus(), sourceFolder).Count();
var dayNumber = (int)DateTime.Today.DayOfWeek;
skip = dayNumber * count / 7;
take = count / 7 + 1;
Console.WriteLine($"Comparing {take:n0} files starting on index {skip:n0}");
}
CompareStatus status = new CompareStatus();
status.Stopwatch.Start();
using (var timer = new Timer(new TimerCallback((s) => PrintStatus(s)), status, 5000, 5000))
{
CompareFolders(status, sourceFolder, destinationFolder, skip, take);
}
status.Stopwatch.Stop();
Console.WriteLine($"Completed in: {status.Stopwatch.Elapsed}; Total size: {status.BytesRead:n0}; Total files: {status.Total}; Missing: {status.Missing}; Different: {status.Different}");
Environment.Exit((int)
(ReturnCodes.NoErrors |
(status.Missing > 0 ? ReturnCodes.MissingFile : ReturnCodes.NoErrors) |
(status.Different > 0 ? ReturnCodes.DifferentFile : ReturnCodes.NoErrors) |
(status.DirectoryNoAccess > 0 ? ReturnCodes.DirectoryNoAccess: ReturnCodes.NoErrors) |
(status.NoAccess > 0 ? ReturnCodes.NoAccess : ReturnCodes.NoErrors)));
}
private static void PrintStatus(object state)
{
var status = (CompareStatus)state;
Console.WriteLine($"{status.BytesRead / 1024 / 1024:n0} MB read; Speed: {status.BytesRead / status.Stopwatch.Elapsed.TotalSeconds / 1000:n0} KB/s");
}
private static void CompareFolders(CompareStatus status, string sourceFolder, string destinationFolder, int? skip, int? take)
{
var files = FileAccess.GetFiles(status, sourceFolder);
files = skip.HasValue && take.HasValue ? files.Skip(skip.Value).Take(take.Value) : files;
foreach (var sourceFile in files)
{
var destinationFile = sourceFile.Replace(sourceFolder, destinationFolder);
status.Total++;
if (!File.Exists(destinationFile))
{
Console.WriteLine("Missing: " + destinationFile);
status.Missing++;
continue;
}
if (!CompareFiles(status, sourceFile, destinationFile))
{
Console.WriteLine("File is different: " + destinationFile);
status.Different++;
}
}
}
private static bool CompareFiles(CompareStatus status, string sourceFile, string destinationFile)
{
var blockSize = 64 * 1024;
var sourceBuffer = new byte[blockSize];
var destinationBuffer = new byte[blockSize];
using (var sourceStream = FileAccess.OpenFile(sourceFile))
using (var destinationStream = FileAccess.OpenFile(destinationFile))
{
if (sourceStream == null || destinationStream == null)
{
status.NoAccess++;
}
else
{
while (true)
{
var sourceRead = sourceStream.ReadAsync(sourceBuffer, 0, blockSize);
var destinationRead = destinationStream.ReadAsync(destinationBuffer, 0, blockSize);
if (sourceRead.Result == 0)
{
break;
}
status.BytesRead += sourceRead.Result;
if (sourceRead.Result != destinationRead.Result)
{
return false;
}
if (!ArrayCompare.CompareArraysUnsafe(sourceBuffer, destinationBuffer, sourceBuffer.Length))
{
return false;
}
}
}
}
return true;
}
private static void CheckFolderExists(string folder)
{
if (!Directory.Exists(folder))
{
Console.Error.WriteLine("Folder does not exist: " + folder);
Environment.Exit((int)ReturnCodes.InvalidArguments);
}
}
private static void Usage()
{
Console.Error.WriteLine("FolderCompare.exe <folder1> <folder2> [/slice]");
Console.WriteLine(" Return codes (ORed bits)");
foreach (var returnCode in Enum.GetValues(typeof(ReturnCodes)))
{
Console.Error.WriteLine($" -- {returnCode}: {(int)returnCode}");
}
Environment.Exit((int)ReturnCodes.InvalidArguments);
}
}
}