일반적인 접근 방식 은 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;
}
답변
만약 당신 이 진정으로 전체 바이트 단위 비교 가 필요하다고 결정한다면 (해싱에 대한 다른 답변을보십시오) 가장 쉬운 해결책은 다음과 같습니다 :
• 예를 System.IO.FileInfo
들면 :
public static bool AreFileContentsEqual(FileInfo fi1, FileInfo fi2) =>
fi1.Length == fi2.Length &&
(fi1.Length == 0 || File.ReadAllBytes(fi1.FullName).SequenceEqual(
File.ReadAllBytes(fi2.FullName)));
• System.String
경로 이름 :
public static bool AreFileContentsEqual(String path1, String path2) =>
AreFileContentsEqual(new FileInfo(path1), new FileInfo(path2));
게시 된 다른 답변과 달리 이것은 바이너리, 텍스트, 미디어, 실행 파일 등 모든 종류의 파일에 대해 결정적으로 정확 하지만 완전한 바이너리 비교 로 “중요하지 않은”방법 만 다른 파일 (예 : BOM , 줄) -ending , 문자 인코딩 , 미디어 메타 데이터, 공백, 패딩, 소스 코드 주석 등은 항상 같지 않은 것으로 간주됩니다 .
이 코드는 두 파일을 모두 메모리에 완전히로드하므로 실제로 거대한 파일 을 비교하는 데 사용 해서는 안됩니다 . 중요주의를 넘어, 전체로드는 .NET의 디자인 주어진 페널티 킥 정말 아니다 GC는 (그것은 근본적으로 작은 유지하기 위해 최적화 있기 때문에 단명 할당 매우 싼 ), 때 사실도 최적이 될 수 파일 크기가 예상된다 이상이어야 85K (다음과 같이) 사용자의 최소한의 코드를 사용하여 최대한으로 파일 성능 문제를 위임하는 것을 의미하기 때문에, CLR
, BCL
, 및 JIT
(예를 들어) 최신 설계 기술, 시스템 코드, 및 적응 런타임 최적화의 혜택을.
또한 이러한 임시 시나리오의 경우 LINQ
열거자를 통해 바이트 단위 비교 성능에 대한 우려가 불분명합니다 ( 파일 I / O에 대해 디스크 ahitt̲ a̲l̲l̲ 를 때리면 몇 배씩 줄어듦). 다양한 메모리 비교 대안 중 하나. 예를 들어, 비록 SequenceEqual
않는 사실 우리의 “최적화”제공 첫 불일치에 포기를 이 거의 파일 ‘내용을 이미 가지고 가져온 후, 각 완전히 필요한 경기를 확인하기 위해 중요하지 ..
답변
리드 콥시 의 답변 외에도 :
-
최악의 경우 두 파일이 동일합니다. 이 경우 파일을 바이트 단위로 비교하는 것이 가장 좋습니다.
-
두 파일이 동일하지 않으면 파일이 동일하지 않다는 것을 빨리 감지하여 속도를 높일 수 있습니다.
예를 들어, 두 파일의 길이가 다른 경우 파일이 동일 할 수 없으며 실제 내용을 비교할 필요조차 없다는 것을 알 수 있습니다.
답변
작은 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));