C #에서 큰 파일에 대한 체크섬을 만드는 가장 빠른 방법은 무엇입니까
일부 컴퓨터에서 큰 파일을 동기화해야합니다. 파일 크기는 최대 6GB입니다. 동기화는 몇 주마다 수동으로 수행됩니다. 파일 이름은 언제든지 변경할 수 있으므로 고려할 수 없습니다.
내 계획은 대상 PC와 원본 PC에서 체크섬을 만든 다음 아직 대상에없는 체크섬이있는 모든 파일을 대상에 복사하는 것입니다. 내 첫 번째 시도는 다음과 같습니다.
using System.IO;
using System.Security.Cryptography;
private static string GetChecksum(string file)
{
using (FileStream stream = File.OpenRead(file))
{
SHA256Managed sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
런타임 문제 :
-1,6GB 파일이있는 SHA256-> 20 분
-1,6GB 파일이있는 MD5-> 6.15 분
체크섬을 얻는 더 좋고 빠른 방법이 있습니까?
여기서 문제는 SHA256Managed
한 번에 4096 바이트 를 읽고 ( 파일 스트림에서 읽은 양을 확인하기 위해 상속 FileStream
하고 대체 Read(byte[], int, int)
함) 디스크 IO에 비해 너무 작은 버퍼입니다.
속도 일까지 랩 (2 내 SHA256와 기계, MD5 1 분 정도에 2GB의 파일을 해싱 분) FileStream
에 BufferedStream
설정하고 합리적인 크기의 버퍼 크기 (나는 ~ 1 메가 버퍼로 시도) :
// Not sure if BufferedStream should be wrapped in using block
using(var stream = new BufferedStream(File.OpenRead(filePath), 1200000))
{
// The rest remains the same
}
전체 파일을 체크섬하지 말고 100MB 정도마다 체크섬을 생성하십시오. 따라서 각 파일에는 체크섬 모음이 있습니다.
그런 다음 체크섬을 비교할 때 첫 번째 다른 체크섬 후 비교를 중지하고 일찍 나가 전체 파일을 처리하지 않아도됩니다.
동일한 파일의 경우 여전히 풀 타임이 소요됩니다.
Anton Gogolev가 언급했듯이 FileStream은 기본적으로 한 번에 4096 바이트를 읽지 만 FileStream 생성자를 사용하여 다른 값을 지정할 수 있습니다.
new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)
Microsoft의 Brad Abrams는 2004 년에 다음과 같이 썼습니다.
FileStream 주위에 BufferedStream을 래핑하면 이점이 없습니다. 약 4 년 전에 BufferedStream의 버퍼링 로직을 FileStream에 복사하여 기본 성능을 향상 시켰습니다.
md5sum.exe 의 Windows 포트를 호출하십시오 . .NET 구현보다 약 2 배 빠릅니다 (적어도 1.2GB 파일을 사용하는 컴퓨터에서는)
public static string Md5SumByProcess(string file) {
var p = new Process ();
p.StartInfo.FileName = "md5sum.exe";
p.StartInfo.Arguments = file;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
return output.Split(' ')[0].Substring(1).ToUpper ();
}
좋아요-모두 감사합니다. 마무리하겠습니다.
- "네이티브"exe 를 사용하여 해싱을 수행하는 데 6 분에서 10 초까지 걸리는 시간은 엄청났습니다.
- Increasing the buffer was even faster - 1.6GB file took 5.2 seconds using MD5 in .Net, so I will go with this solution - thanks again
I did tests with buffer size, running this code
using (var stream = new BufferedStream(File.OpenRead(file), bufferSize))
{
SHA256Managed sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
}
And I tested with a file of 29½ GB in size, the results were
- 10.000: 369,24s
- 100.000: 362,55s
- 1.000.000: 361,53s
- 10.000.000: 434,15s
- 100.000.000: 435,15s
- 1.000.000.000: 434,31s
- And 376,22s when using the original, none buffered code.
I am running an i5 2500K CPU, 12 GB ram and a OCZ Vertex 4 256 GB SSD drive.
So I thought, what about a standard 2TB harddrive. And the results were like this
- 10.000: 368,52s
- 100.000: 364,15s
- 1.000.000: 363,06s
- 10.000.000: 678,96s
- 100.000.000: 617,89s
- 1.000.000.000: 626,86s
- And for none buffered 368,24
So I would recommend either no buffer or a buffer of max 1 mill.
You're doing something wrong (probably too small read buffer). On a machine of undecent age (Athlon 2x1800MP from 2002) that has DMA on disk probably out of whack (6.6M/s is damn slow when doing sequential reads):
Create a 1G file with "random" data:
# dd if=/dev/sdb of=temp.dat bs=1M count=1024
1073741824 bytes (1.1 GB) copied, 161.698 s, 6.6 MB/s
# time sha1sum -b temp.dat
abb88a0081f5db999d0701de2117d2cb21d192a2 *temp.dat
1m5.299s
# time md5sum -b temp.dat
9995e1c1a704f9c1eb6ca11e7ecb7276 *temp.dat
1m58.832s
This is also weird, md5 is consistently slower than sha1 for me (reran several times).
I know that I am late to party but performed test before actually implement the solution.
I did perform test against inbuilt MD5 class and also md5sum.exe. In my case inbuilt class took 13 second where md5sum.exe too around 16-18 seconds in every run.
DateTime current = DateTime.Now;
string file = @"C:\text.iso";//It's 2.5 Gb file
string output;
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(file))
{
byte[] checksum = md5.ComputeHash(stream);
output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
}
}
'Programing' 카테고리의 다른 글
파이썬에서 변수가 없음, 참 또는 거짓인지 어떻게 테스트해야합니까? (0) | 2020.07.07 |
---|---|
열거 형이 가질 수있는 모든 값을 가져 오는 SQL 쿼리 (0) | 2020.07.07 |
마지막 요소를 얻는 XSLT (0) | 2020.07.07 |
루비 % r {} 표현식 (0) | 2020.07.07 |
vim의 모든 줄 끝에서 ^ M (0) | 2020.07.07 |