.NET을 사용하여 두 파일을 빠르게 비교하는 방법은 무엇입니까?
일반적인 접근 방식 은 FileStream을 통해 바이너리를 읽고 바이트 단위로 비교하는 것이 좋습니다.
- CRC와 같은 체크섬 비교가 더 빠릅니까?
- 파일의 체크섬을 생성 할 수있는 .NET 라이브러리가 있습니까?
체크섬 비교는 바이트 단위 비교보다 느릴 수 있습니다.
체크섬을 생성하려면 파일의 각 바이트를로드하고 처리해야합니다. 그런 다음 두 번째 파일에서이 작업을 수행해야합니다. 비교 검사보다 처리 속도가 거의 느려질 것입니다.
체크섬 생성 : 암호화 클래스를 사용하여이 작업을 쉽게 수행 할 수 있습니다. 다음 은 C #으로 MD5 체크섬을 생성하는 간단한 예입니다 .
그러나 "테스트"또는 "기본"사례의 체크섬을 미리 계산할 수 있으면 체크섬이 더 빠르고 더 의미가있을 수 있습니다. 기존 파일이 있고 새 파일이 기존 파일과 동일한 지 확인하려는 경우 "기존"파일의 체크섬을 사전 계산하면 DiskIO를 한 번만 수행하면됩니다. 새로운 파일. 이것은 바이트 단위 비교보다 빠를 것입니다.
가장 느린 방법은 두 파일을 바이트 단위로 비교하는 것입니다. 내가 찾은 가장 빠른 비교는 비슷한 비교이지만 한 번에 1 바이트 대신 Int64 크기의 바이트 배열을 사용한 다음 결과 숫자를 비교합니다.
내가 생각해 낸 것은 다음과 같습니다.
const int BYTES_TO_READ = sizeof(Int64);
static bool FilesAreEqual(FileInfo first, FileInfo second)
{
if (first.Length != second.Length)
return false;
if (string.Equals(first.FullName, second.FullName, StringComparison.OrdinalIgnoreCase))
return true;
int iterations = (int)Math.Ceiling((double)first.Length / BYTES_TO_READ);
using (FileStream fs1 = first.OpenRead())
using (FileStream fs2 = second.OpenRead())
{
byte[] one = new byte[BYTES_TO_READ];
byte[] two = new byte[BYTES_TO_READ];
for (int i = 0; i < iterations; i++)
{
fs1.Read(one, 0, BYTES_TO_READ);
fs2.Read(two, 0, BYTES_TO_READ);
if (BitConverter.ToInt64(one,0) != BitConverter.ToInt64(two,0))
return false;
}
}
return true;
}
필자의 테스트에서 이는 간단한 3 : 1만큼 간단한 ReadByte () 시나리오보다 성능이 뛰어남을 알 수있었습니다. 평균 1000 회 이상 실행되면 1063ms 에서이 방법을 얻었고 3031ms에서 아래의 방법 (바이트 단위 비교)을 얻었습니다. 해싱은 항상 평균 865ms에서 1 초 미만으로 돌아 왔습니다. 이 테스트는 ~ 100MB 비디오 파일로 수행되었습니다.
비교 목적으로 사용한 ReadByte 및 해싱 방법은 다음과 같습니다.
static bool FilesAreEqual_OneByte(FileInfo first, FileInfo second)
{
if (first.Length != second.Length)
return false;
if (string.Equals(first.FullName, second.FullName, StringComparison.OrdinalIgnoreCase))
return true;
using (FileStream fs1 = first.OpenRead())
using (FileStream fs2 = second.OpenRead())
{
for (int i = 0; i < first.Length; i++)
{
if (fs1.ReadByte() != fs2.ReadByte())
return false;
}
}
return true;
}
static bool FilesAreEqual_Hash(FileInfo first, FileInfo second)
{
byte[] firstHash = MD5.Create().ComputeHash(first.OpenRead());
byte[] secondHash = MD5.Create().ComputeHash(second.OpenRead());
for (int i=0; i<firstHash.Length; i++)
{
if (firstHash[i] != secondHash[i])
return false;
}
return true;
}
만약 당신 이 진정으로 전체 바이트 단위 비교 가 필요하다고 결정한다면 (해싱에 대한 다른 답변을보십시오), 한 줄 해결책은 다음과 같습니다 :
bool filesAreEqual = File.ReadAllBytes(path1).SequenceEqual(File.ReadAllBytes(path2));
게시 된 다른 답변과 달리 이진, 텍스트, 미디어, 실행 파일 등 모든 종류의 파일에서 올바르게 작동 하지만 전체 이진 비교 로 "중요하지 않은"방법 만 다른 파일 (예 : BOM , line- 종료 , 문자 인코딩 , 미디어 메타 데이터, 공백, 패딩, 소스 코드 주석 등은) 항상 간주됩니다 같지 않음 .
이 코드는 두 파일을 모두 메모리에 완전히로드하므로 거대한 파일 을 비교하는 데 사용해서는 안됩니다 . 이러한 고려 사항 외에도 전체 로딩은 실제로 페널티가 아닙니다. 실제로 이것은 작은 크기의 할당 이 매우 저렴하고 위의 코드가 파일 성능과 최적화를 /에 최대로 위임 하기 때문에 파일 크기에 대한 최적의 .NET 솔루션이 85K 미만일 것으로 예상됩니다 ..NET
CLR
BCL
또한 이러한 임시 시나리오의 경우 LINQ
열거자를 통한 바이트 별 비교 성능에 대한 우려가 불분명합니다 ( 파일 I / O에 대해 디스크 ahitt̲ a̲l̲l̲ 를 때리면 몇 배씩 줄어듦). 다양한 메모리 비교 대안 중 하나. 예를 들어, 비록 SequenceEqual
않는 사실 우리의 "최적화"제공 첫 불일치에 포기를 이 거의 파일 '내용을 이미 가지고 가져온 후, 각 완전히 필요한 경기를 확인하기 위해 중요하지 ..
한편, 위의 코드는 하지 않습니다 에 대한 열망 중단 등 다른 크기의 파일 , 수 실체 (아마도 측정) 성능 차이를 제공합니다. 파일 길이는 WIN32_FILE_ATTRIBUTE_DATA
구조 에서 사용 가능하지만 (어쨌든 파일 액세스를 위해 먼저 가져와야 함) 파일의 내용에 계속 액세스하려면 피할 수있는 완전히 다른 가져 오기가 필요 하기 때문에이 유형이 가능 합니다. 이것에 대해 걱정한다면 해결책은 두 줄이됩니다.
// slight optimization over the code shown above
bool filesAreEqual = new FileInfo(path1).Length == new FileInfo(path2).Length &&
File.ReadAllBytes(path1).SequenceEqual(File.ReadAllBytes(path2));
(동등한) Length
값이 모두 0으로 표시되고 (나타내지 않음) 각 FileInfo
두 번의 빌드를 피하기 위해 (또는 표시되지 않음) 보조 페치를 피하기 위해이를 확장 할 수도 있습니다 .
리드 콥시 의 답변 외에도 :
최악의 경우 두 파일이 동일합니다. 이 경우 파일을 바이트 단위로 비교하는 것이 가장 좋습니다.
두 파일이 동일하지 않으면 파일이 동일하지 않다는 것을 빨리 감지하여 속도를 높일 수 있습니다.
예를 들어, 두 파일의 길이가 다른 경우 파일이 동일 할 수 없으며 실제 내용을 비교할 필요조차 없다는 것을 알 수 있습니다.
작은 8 바이트 청크를 읽지 않고 더 큰 청크를 읽으면 루프를 돌리면 훨씬 빨라집니다. 평균 비교 시간을 1/4로 줄였습니다.
public static bool FilesContentsAreEqual(FileInfo fileInfo1, FileInfo fileInfo2)
{
bool result;
if (fileInfo1.Length != fileInfo2.Length)
{
result = false;
}
else
{
using (var file1 = fileInfo1.OpenRead())
{
using (var file2 = fileInfo2.OpenRead())
{
result = StreamsContentsAreEqual(file1, file2);
}
}
}
return result;
}
private static bool StreamsContentsAreEqual(Stream stream1, Stream stream2)
{
const int bufferSize = 1024 * sizeof(Int64);
var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];
while (true)
{
int count1 = stream1.Read(buffer1, 0, bufferSize);
int count2 = stream2.Read(buffer2, 0, bufferSize);
if (count1 != count2)
{
return false;
}
if (count1 == 0)
{
return true;
}
int iterations = (int)Math.Ceiling((double)count1 / sizeof(Int64));
for (int i = 0; i < iterations; i++)
{
if (BitConverter.ToInt64(buffer1, i * sizeof(Int64)) != BitConverter.ToInt64(buffer2, i * sizeof(Int64)))
{
return false;
}
}
}
}
}
바이트 단위 비교보다 체크섬 비교가 약간 더 빠를 수있는 유일한 방법은 한 번에 하나의 파일을 읽고 디스크 헤드의 탐색 시간을 다소 단축한다는 것입니다. 그러나 약간의 이득은 해시 계산에 추가 된 시간에 의해 매우 잘 흡수 될 수 있습니다.
또한 파일의 체크섬 비교는 파일이 동일한 경우에만 더 빠를 가능성이 있습니다. 그렇지 않은 경우, 바이트 별 비교는 첫 번째 차이로 끝나서 훨씬 빠릅니다.
또한 해시 코드 비교 는 파일이 동일 할 가능성 이 높다는 것을 알려줍니다 . 100 % 확실하게하려면 바이트 단위 비교를 수행해야합니다.
예를 들어 해시 코드가 32 비트 인 경우 해시 코드가 일치하면 파일이 동일한 지 약 99.99999998 %입니다. 100 %에 가깝지만 100 % 확실성이 필요한 경우에는 그렇지 않습니다.
편집 : 이 방법은 이진 파일을 비교 하는 데 사용할 수 없습니다 !
.NET 4.0에서 File
클래스에는 다음 두 가지 새로운 메소드가 있습니다.
public static IEnumerable<string> ReadLines(string path)
public static IEnumerable<string> ReadLines(string path, Encoding encoding)
다음을 사용할 수 있음을 의미합니다.
bool same = File.ReadLines(path1).SequenceEqual(File.ReadLines(path2));
솔직히 검색 트리를 최대한 정리해야한다고 생각합니다.
바이트 단위로 가기 전에 확인해야 할 사항 :
- 크기가 동일합니까?
- 파일 A의 마지막 바이트가 파일 B와 다릅니다
또한 드라이브가 순차적 바이트를보다 빨리 읽으므로 한 번에 큰 블록을 읽는 것이 더 효율적입니다. 바이트 단위로 이동하면 더 많은 시스템 호출이 발생할뿐만 아니라 두 파일이 모두 같은 드라이브에있는 경우 기존 하드 드라이브의 읽기 헤드가 더 자주 검색됩니다.
청크 A와 청크 B를 바이트 버퍼로 읽고 비교하십시오 (배열을 사용하지 마십시오. 주석 참조). 메모리와 성능 사이에서 균형이 잘 맞다고 생각 될 때까지 블록의 크기를 조정하십시오. 비교를 멀티 스레딩 할 수도 있지만 디스크 읽기를 멀티 스레딩하지 마십시오.
내 대답은 @lars의 파생이지만에 대한 호출에서 버그를 수정합니다 Stream.Read
. 또한 다른 답변의 빠른 경로 확인 및 입력 유효성 검사를 추가합니다. 즉,이해야 대답 :
using System;
using System.IO;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
var fi1 = new FileInfo(args[0]);
var fi2 = new FileInfo(args[1]);
Console.WriteLine(FilesContentsAreEqual(fi1, fi2));
}
public static bool FilesContentsAreEqual(FileInfo fileInfo1, FileInfo fileInfo2)
{
if (fileInfo1 == null)
{
throw new ArgumentNullException(nameof(fileInfo1));
}
if (fileInfo2 == null)
{
throw new ArgumentNullException(nameof(fileInfo2));
}
if (string.Equals(fileInfo1.FullName, fileInfo2.FullName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (fileInfo1.Length != fileInfo2.Length)
{
return false;
}
else
{
using (var file1 = fileInfo1.OpenRead())
{
using (var file2 = fileInfo2.OpenRead())
{
return StreamsContentsAreEqual(file1, file2);
}
}
}
}
private static int ReadFullBuffer(Stream stream, byte[] buffer)
{
int bytesRead = 0;
while (bytesRead < buffer.Length)
{
int read = stream.Read(buffer, bytesRead, buffer.Length - bytesRead);
if (read == 0)
{
// Reached end of stream.
return bytesRead;
}
bytesRead += read;
}
return bytesRead;
}
private static bool StreamsContentsAreEqual(Stream stream1, Stream stream2)
{
const int bufferSize = 1024 * sizeof(Int64);
var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];
while (true)
{
int count1 = ReadFullBuffer(stream1, buffer1);
int count2 = ReadFullBuffer(stream2, buffer2);
if (count1 != count2)
{
return false;
}
if (count1 == 0)
{
return true;
}
int iterations = (int)Math.Ceiling((double)count1 / sizeof(Int64));
for (int i = 0; i < iterations; i++)
{
if (BitConverter.ToInt64(buffer1, i * sizeof(Int64)) != BitConverter.ToInt64(buffer2, i * sizeof(Int64)))
{
return false;
}
}
}
}
}
}
또는 대단하고 싶다면 비동기 변형을 사용할 수 있습니다.
using System;
using System.IO;
using System.Threading.Tasks;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
var fi1 = new FileInfo(args[0]);
var fi2 = new FileInfo(args[1]);
Console.WriteLine(FilesContentsAreEqualAsync(fi1, fi2).GetAwaiter().GetResult());
}
public static async Task<bool> FilesContentsAreEqualAsync(FileInfo fileInfo1, FileInfo fileInfo2)
{
if (fileInfo1 == null)
{
throw new ArgumentNullException(nameof(fileInfo1));
}
if (fileInfo2 == null)
{
throw new ArgumentNullException(nameof(fileInfo2));
}
if (string.Equals(fileInfo1.FullName, fileInfo2.FullName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (fileInfo1.Length != fileInfo2.Length)
{
return false;
}
else
{
using (var file1 = fileInfo1.OpenRead())
{
using (var file2 = fileInfo2.OpenRead())
{
return await StreamsContentsAreEqualAsync(file1, file2).ConfigureAwait(false);
}
}
}
}
private static async Task<int> ReadFullBufferAsync(Stream stream, byte[] buffer)
{
int bytesRead = 0;
while (bytesRead < buffer.Length)
{
int read = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead).ConfigureAwait(false);
if (read == 0)
{
// Reached end of stream.
return bytesRead;
}
bytesRead += read;
}
return bytesRead;
}
private static async Task<bool> StreamsContentsAreEqualAsync(Stream stream1, Stream stream2)
{
const int bufferSize = 1024 * sizeof(Int64);
var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];
while (true)
{
int count1 = await ReadFullBufferAsync(stream1, buffer1).ConfigureAwait(false);
int count2 = await ReadFullBufferAsync(stream2, buffer2).ConfigureAwait(false);
if (count1 != count2)
{
return false;
}
if (count1 == 0)
{
return true;
}
int iterations = (int)Math.Ceiling((double)count1 / sizeof(Int64));
for (int i = 0; i < iterations; i++)
{
if (BitConverter.ToInt64(buffer1, i * sizeof(Int64)) != BitConverter.ToInt64(buffer2, i * sizeof(Int64)))
{
return false;
}
}
}
}
}
}
필자의 실험에 따르면 Stream.ReadByte ()를 더 적은 횟수로 호출하는 것이 확실히 도움이되지만 BitConverter를 사용하여 바이트를 패키지하면 바이트 배열의 바이트를 비교하는 데 큰 차이가 없습니다.
따라서 위 주석에서 "Math.Ceiling and iterations"루프를 가장 간단한 것으로 바꿀 수 있습니다.
for (int i = 0; i < count1; i++)
{
if (buffer1[i] != buffer2[i])
return false;
}
BitConverter.ToInt64는 비교하기 전에 약간의 작업 (인수를 확인한 다음 비트 이동을 수행해야 함)이 필요하다는 사실과 관련이 있다고 생각합니다. .
파일이 너무 크지 않으면 다음을 사용할 수 있습니다.
public static byte[] ComputeFileHash(string fileName)
{
using (var stream = File.OpenRead(fileName))
return System.Security.Cryptography.MD5.Create().ComputeHash(stream);
}
해시를 저장하는 것이 유용한 경우에만 해시를 비교하는 것이 가능합니다.
(코드를 훨씬 더 깨끗한 것으로 편집했습니다.)
길이가 같은 큰 파일의 또 다른 개선점은 파일을 순차적으로 읽지 않고 임의의 블록을 비교하는 것입니다.
파일의 다른 위치에서 시작하여 앞뒤로 비교하는 여러 스레드를 사용할 수 있습니다.
이렇게하면 순차적 접근 방식을 사용하는 것보다 빠르게 파일의 중간 / 끝에서 변경 사항을 감지 할 수 있습니다.
두 파일 만 비교 해야하는 경우 가장 빠른 방법은 다음과 같습니다 (C에서는 .NET에 해당되는지 알 수 없습니다)
- 두 파일 f1, f2를 엽니 다
- 각각의 파일 길이 l1, l2를 얻습니다.
- l1! = l2이면 파일이 다릅니다. 중지
- mmap () 두 파일
- mmap () 파일에서 memcmp () 사용
OTOH, N 파일 세트에 중복 파일이 있는지 확인 해야하는 경우 가장 빠른 방법은 N- 비트 비트 비교를 피하기 위해 해시를 사용하는 것입니다.
합리적으로 효율적인 것 :
public class FileCompare
{
public static bool FilesEqual(string fileName1, string fileName2)
{
return FilesEqual(new FileInfo(fileName1), new FileInfo(fileName2));
}
/// <summary>
///
/// </summary>
/// <param name="file1"></param>
/// <param name="file2"></param>
/// <param name="bufferSize">8kb seemed like a good default</param>
/// <returns></returns>
public static bool FilesEqual(FileInfo file1, FileInfo file2, int bufferSize = 8192)
{
if (!file1.Exists || !file2.Exists || file1.Length != file2.Length) return false;
var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];
using (var stream1 = file1.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var stream2 = file2.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
while (true)
{
var bytesRead1 = stream1.Read(buffer1, 0, bufferSize);
var bytesRead2 = stream2.Read(buffer2, 0, bufferSize);
if (bytesRead1 != bytesRead2) return false;
if (bytesRead1 == 0) return true;
if (!ArraysEqual(buffer1, buffer2, bytesRead1)) return false;
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="array1"></param>
/// <param name="array2"></param>
/// <param name="bytesToCompare"> 0 means compare entire arrays</param>
/// <returns></returns>
public static bool ArraysEqual(byte[] array1, byte[] array2, int bytesToCompare = 0)
{
if (array1.Length != array2.Length) return false;
var length = (bytesToCompare == 0) ? array1.Length : bytesToCompare;
var tailIdx = length - length % sizeof(Int64);
//check in 8 byte chunks
for (var i = 0; i < tailIdx; i += sizeof(Int64))
{
if (BitConverter.ToInt64(array1, i) != BitConverter.ToInt64(array2, i)) return false;
}
//check the remainder of the array, always shorter than 8 bytes
for (var i = tailIdx; i < length; i++)
{
if (array1[i] != array2[i]) return false;
}
return true;
}
}
다음은 두 개의 파일 (또는 두 개의 스트림)에 동일한 데이터가 포함되어 있는지 확인할 수있는 유틸리티 기능입니다.
Tasks를 사용하여 다른 스레드에서 바이트 배열 (각 파일에서 읽은 내용으로 채워진 각 버퍼)을 비교할 때 다중 스레드 인 "빠른"버전을 제공했습니다.
예상대로 훨씬 빠르지 만 (약 3 배 빠름) 더 많은 CPU (멀티 스레드이기 때문에)와 더 많은 메모리를 소비합니다 (비교 스레드 당 2 바이트 배열 버퍼가 필요하기 때문에).
public static bool AreFilesIdenticalFast(string path1, string path2)
{
return AreFilesIdentical(path1, path2, AreStreamsIdenticalFast);
}
public static bool AreFilesIdentical(string path1, string path2)
{
return AreFilesIdentical(path1, path2, AreStreamsIdentical);
}
public static bool AreFilesIdentical(string path1, string path2, Func<Stream, Stream, bool> areStreamsIdentical)
{
if (path1 == null)
throw new ArgumentNullException(nameof(path1));
if (path2 == null)
throw new ArgumentNullException(nameof(path2));
if (areStreamsIdentical == null)
throw new ArgumentNullException(nameof(path2));
if (!File.Exists(path1) || !File.Exists(path2))
return false;
using (var thisFile = new FileStream(path1, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var valueFile = new FileStream(path2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
if (valueFile.Length != thisFile.Length)
return false;
if (!areStreamsIdentical(thisFile, valueFile))
return false;
}
}
return true;
}
public static bool AreStreamsIdenticalFast(Stream stream1, Stream stream2)
{
if (stream1 == null)
throw new ArgumentNullException(nameof(stream1));
if (stream2 == null)
throw new ArgumentNullException(nameof(stream2));
const int bufsize = 80000; // 80000 is below LOH (85000)
var tasks = new List<Task<bool>>();
do
{
// consumes more memory (two buffers for each tasks)
var buffer1 = new byte[bufsize];
var buffer2 = new byte[bufsize];
int read1 = stream1.Read(buffer1, 0, buffer1.Length);
if (read1 == 0)
{
int read3 = stream2.Read(buffer2, 0, 1);
if (read3 != 0) // not eof
return false;
break;
}
// both stream read could return different counts
int read2 = 0;
do
{
int read3 = stream2.Read(buffer2, read2, read1 - read2);
if (read3 == 0)
return false;
read2 += read3;
}
while (read2 < read1);
// consumes more cpu
var task = Task.Run(() =>
{
return IsSame(buffer1, buffer2);
});
tasks.Add(task);
}
while (true);
Task.WaitAll(tasks.ToArray());
return !tasks.Any(t => !t.Result);
}
public static bool AreStreamsIdentical(Stream stream1, Stream stream2)
{
if (stream1 == null)
throw new ArgumentNullException(nameof(stream1));
if (stream2 == null)
throw new ArgumentNullException(nameof(stream2));
const int bufsize = 80000; // 80000 is below LOH (85000)
var buffer1 = new byte[bufsize];
var buffer2 = new byte[bufsize];
var tasks = new List<Task<bool>>();
do
{
int read1 = stream1.Read(buffer1, 0, buffer1.Length);
if (read1 == 0)
return stream2.Read(buffer2, 0, 1) == 0; // check not eof
// both stream read could return different counts
int read2 = 0;
do
{
int read3 = stream2.Read(buffer2, read2, read1 - read2);
if (read3 == 0)
return false;
read2 += read3;
}
while (read2 < read1);
if (!IsSame(buffer1, buffer2))
return false;
}
while (true);
}
public static bool IsSame(byte[] bytes1, byte[] bytes2)
{
if (bytes1 == null)
throw new ArgumentNullException(nameof(bytes1));
if (bytes2 == null)
throw new ArgumentNullException(nameof(bytes2));
if (bytes1.Length != bytes2.Length)
return false;
for (int i = 0; i < bytes1.Length; i++)
{
if (bytes1[i] != bytes2[i])
return false;
}
return true;
}
"해시"가 바이트 단위로 비교하는 것보다 빠른 응용 프로그램이 있다고 생각합니다. 파일을 다른 파일과 비교해야하거나 변경할 수있는 사진의 썸네일이있는 경우. 사용 위치와 방법에 따라 다릅니다.
private bool CompareFilesByte(string file1, string file2)
{
using (var fs1 = new FileStream(file1, FileMode.Open))
using (var fs2 = new FileStream(file2, FileMode.Open))
{
if (fs1.Length != fs2.Length) return false;
int b1, b2;
do
{
b1 = fs1.ReadByte();
b2 = fs2.ReadByte();
if (b1 != b2 || b1 < 0) return false;
}
while (b1 >= 0);
}
return true;
}
private string HashFile(string file)
{
using (var fs = new FileStream(file, FileMode.Open))
using (var reader = new BinaryReader(fs))
{
var hash = new SHA512CryptoServiceProvider();
hash.ComputeHash(reader.ReadBytes((int)file.Length));
return Convert.ToBase64String(hash.Hash);
}
}
private bool CompareFilesWithHash(string file1, string file2)
{
var str1 = HashFile(file1);
var str2 = HashFile(file2);
return str1 == str2;
}
여기서 가장 빠른 것을 얻을 수 있습니다.
var sw = new Stopwatch();
sw.Start();
var compare1 = CompareFilesWithHash(receiveLogPath, logPath);
sw.Stop();
Debug.WriteLine(string.Format("Compare using Hash {0}", sw.ElapsedTicks));
sw.Reset();
sw.Start();
var compare2 = CompareFilesByte(receiveLogPath, logPath);
sw.Stop();
Debug.WriteLine(string.Format("Compare byte-byte {0}", sw.ElapsedTicks));
선택적으로 해시를 데이터베이스에 저장할 수 있습니다.
이것이 도움이되기를 바랍니다.
@chsh에서 파생 된 또 다른 대답. 파일에 대한 사용 및 바로 가기가있는 MD5, 파일이 존재하지 않으며 길이가 다릅니다.
/// <summary>
/// Performs an md5 on the content of both files and returns true if
/// they match
/// </summary>
/// <param name="file1">first file</param>
/// <param name="file2">second file</param>
/// <returns>true if the contents of the two files is the same, false otherwise</returns>
public static bool IsSameContent(string file1, string file2)
{
if (file1 == file2)
return true;
FileInfo file1Info = new FileInfo(file1);
FileInfo file2Info = new FileInfo(file2);
if (!file1Info.Exists && !file2Info.Exists)
return true;
if (!file1Info.Exists && file2Info.Exists)
return false;
if (file1Info.Exists && !file2Info.Exists)
return false;
if (file1Info.Length != file2Info.Length)
return false;
using (FileStream file1Stream = file1Info.OpenRead())
using (FileStream file2Stream = file2Info.OpenRead())
{
byte[] firstHash = MD5.Create().ComputeHash(file1Stream);
byte[] secondHash = MD5.Create().ComputeHash(file2Stream);
for (int i = 0; i < firstHash.Length; i++)
{
if (i>=secondHash.Length||firstHash[i] != secondHash[i])
return false;
}
return true;
}
}
이것은 데이터를 읽지 않고 먼저 길이를 비교 한 다음 읽은 바이트 시퀀스를 비교하는 것이 효과적이라는 것을 알았습니다.
private static bool IsFileIdentical(string a, string b)
{
if (new FileInfo(a).Length != new FileInfo(b).Length) return false;
return (File.ReadAllBytes(a).SequenceEqual(File.ReadAllBytes(b)));
}
참고 URL : https://stackoverflow.com/questions/1358510/how-to-compare-2-files-fast-using-net
'Programming' 카테고리의 다른 글
쉼표와 반올림을 갖도록 문자열 번호를 어떻게 포맷 할 수 있습니까? (0) | 2020.07.05 |
---|---|
사전에서 하나의 키에 여러 값을 추가합니다 (0) | 2020.07.05 |
팬더 그룹 및 합계 (0) | 2020.07.05 |
한 번의 마우스 클릭으로 모든 DIV 텍스트 선택 (0) | 2020.07.05 |
문자열을 줄로 나누는 가장 좋은 방법 (0) | 2020.07.05 |