-
-
Save filzrev/c6a020260ae742d5c66f89ef899574e0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class FileComparer | |
{ | |
public static bool CompareEquals(string filePath1, string filePath2, int bufferSize = 65536) | |
{ | |
if (filePath1 == filePath2) return true; | |
var buffer1 = ArrayPool<byte>.Shared.Rent(bufferSize); | |
var buffer2 = ArrayPool<byte>.Shared.Rent(bufferSize); | |
try | |
{ | |
using var handle1 = File.OpenHandle(filePath1, FileMode.Open, FileAccess.Read, options: FileOptions.SequentialScan); | |
using var handle2 = File.OpenHandle(filePath2, FileMode.Open, FileAccess.Read, options: FileOptions.SequentialScan); | |
var length1 = RandomAccess.GetLength(handle1); | |
var length2 = RandomAccess.GetLength(handle2); | |
if (length1 == 0 && length2 == 0) return true; | |
if (length1 != length2) return false; | |
long fileOffset = 0; | |
while (fileOffset != length1) | |
{ | |
var read1 = ReadFully(handle1, fileOffset, buffer1); | |
var read2 = ReadFully(handle2, fileOffset, buffer2); | |
if (read1 != read2) return false; | |
if (!buffer1.AsSpan(0, read1).SequenceEqual(buffer2.AsSpan(0, read2))) | |
{ | |
return false; | |
} | |
fileOffset += read1; | |
} | |
return true; | |
} | |
finally | |
{ | |
ArrayPool<byte>.Shared.Return(buffer1); | |
ArrayPool<byte>.Shared.Return(buffer2); | |
} | |
} | |
public static async ValueTask<bool> CompareEqualsAsync(string filePath1, string filePath2, int bufferSize = 65536, CancellationToken cancellationToken = default) | |
{ | |
if (filePath1 == filePath2) return true; | |
var buffer1 = ArrayPool<byte>.Shared.Rent(bufferSize); | |
var buffer2 = ArrayPool<byte>.Shared.Rent(bufferSize); | |
try | |
{ | |
using var handle1 = File.OpenHandle(filePath1, FileMode.Open, FileAccess.Read, options: FileOptions.SequentialScan | FileOptions.Asynchronous); | |
using var handle2 = File.OpenHandle(filePath2, FileMode.Open, FileAccess.Read, options: FileOptions.SequentialScan | FileOptions.Asynchronous); | |
var length1 = RandomAccess.GetLength(handle1); | |
var length2 = RandomAccess.GetLength(handle2); | |
if (length1 == 0 && length2 == 0) return true; | |
if (length1 != length2) return false; | |
long fileOffset = 0; | |
while (fileOffset != length1) | |
{ | |
// inlined ReadFully | |
int read1 = 0; | |
{ | |
var offset = fileOffset; | |
var buffer = buffer1.AsMemory(); | |
var bufferLength = buffer1.Length; | |
while (read1 < bufferLength) | |
{ | |
var read = await RandomAccess.ReadAsync(handle1, buffer, offset, cancellationToken).ConfigureAwait(false); | |
if (read == 0) break; | |
read1 += read; | |
offset += read; | |
buffer = buffer.Slice(read); | |
} | |
} | |
int read2 = 0; | |
{ | |
var offset = fileOffset; | |
var buffer = buffer2.AsMemory(); | |
var bufferLength = buffer2.Length; | |
while (read2 < bufferLength) | |
{ | |
var read = await RandomAccess.ReadAsync(handle2, buffer, offset, cancellationToken).ConfigureAwait(false); | |
if (read == 0) break; | |
read2 += read; | |
offset += read; | |
buffer = buffer.Slice(read); | |
} | |
} | |
if (read1 != read2) return false; | |
if (!buffer1.AsSpan(0, read1).SequenceEqual(buffer2.AsSpan(0, read2))) | |
{ | |
return false; | |
} | |
fileOffset += read1; | |
} | |
return true; | |
} | |
finally | |
{ | |
ArrayPool<byte>.Shared.Return(buffer1); | |
ArrayPool<byte>.Shared.Return(buffer2); | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
static int ReadFully(SafeFileHandle handle, long fileOffset, Span<byte> buffer) | |
{ | |
int bytesRead = 0; | |
var bufferLength = buffer.Length; | |
while (bytesRead < bufferLength) | |
{ | |
var read = RandomAccess.Read(handle, buffer, fileOffset); | |
if (read == 0) return bytesRead; | |
bytesRead += read; | |
fileOffset += read; | |
buffer = buffer.Slice(read); | |
} | |
return bytesRead; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment