Programing

C #에서 큰 파일에 대한 체크섬을 만드는 가장 빠른 방법은 무엇입니까

lottogame 2020. 7. 7. 07:43
반응형

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의 파일을 해싱 분) FileStreamBufferedStream설정하고 합리적인 크기의 버퍼 크기 (나는 ~ 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 ();
}

좋아요-모두 감사합니다. 마무리하겠습니다.

  1. "네이티브"exe 를 사용하여 해싱을 수행하는 데 6 분에서 10 초까지 걸리는 시간은 엄청났습니다.
  2. 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);
        }
    }

참고URL : https://stackoverflow.com/questions/1177607/what-is-the-fastest-way-to-create-a-checksum-for-large-files-in-c-sharp

반응형