문제

큰 이진 파일 (몇 메가 바이트)을 바이트 배열로 읽는 웹 서버가 있습니다. 서버는 여러 파일을 동시에 읽을 수 있으므로 (다른 페이지 요청) CPU에 너무 많은 세금을 부과하지 않고이 작업을 수행하는 가장 최적화 된 방법을 찾고 있습니다. 아래 코드가 충분합니까?

public byte[] FileToByteArray(string fileName)
{
    byte[] buff = null;
    FileStream fs = new FileStream(fileName, 
                                   FileMode.Open, 
                                   FileAccess.Read);
    BinaryReader br = new BinaryReader(fs);
    long numBytes = new FileInfo(fileName).Length;
    buff = br.ReadBytes((int) numBytes);
    return buff;
}
도움이 되었습니까?

해결책

모든 것을 다음과 같이 대체합니다.

return File.ReadAllBytes(fileName);

그러나 메모리 소비에 대해 걱정하는 경우 ~ 아니다 전체 파일을 한 번에 메모리로 읽으십시오. 당신은 덩어리로 그렇게해야합니다.

다른 팁

나는 여기서 그 대답을 주장 할 수있다 일반적으로 "do n't"입니다. 너가 아니라면 절대적으로 필요합니다 모든 데이터를 한 번에 사용하는 것을 고려하십시오 Stream-기반 API (또는 일부 변형의 판독기 / 반복자). 그건 특히 시스템 부하를 최소화하고 처리량을 최대화하기 위해 여러 병렬 작업 (질문에 의해 제안 된)이있을 때 중요합니다.

예를 들어, 데이터를 발신자에게 스트리밍하는 경우 :

Stream dest = ...
using(Stream source = File.OpenRead(path)) {
    byte[] buffer = new byte[2048];
    int bytesRead;
    while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
        dest.Write(buffer, 0, bytesRead);
    }
}

나는 이것을 생각할 것이다 :

byte[] file = System.IO.File.ReadAllBytes(fileName);

귀하의 코드는 이것에 대해 고려 될 수 있습니다 (파일. ReadalLbytes 대신) :

public byte[] ReadAllBytes(string fileName)
{
    byte[] buffer = null;
    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        buffer = new byte[fs.Length];
        fs.Read(buffer, 0, (int)fs.Length);
    }
    return buffer;
} 

Integer.MaxValue- 읽기 메소드에 의해 배치 된 파일 크기 제한을 참고하십시오. 즉, 한 번에 2GB 청크 만 읽을 수 있습니다.

또한 파일 스트림에 대한 마지막 인수는 버퍼 크기입니다.

나는 또한 읽는 것을 제안 할 것입니다 파일 스트림 그리고 완충 스트림.

항상 가장 빠른 프로파일에 대한 간단한 샘플 프로그램이 가장 유익합니다.

또한 기본 하드웨어는 성능에 큰 영향을 미칩니다. 큰 캐시가있는 서버 기반 하드 디스크 드라이브와 온보드 메모리 캐시가있는 RAID 카드를 사용하고 있습니까? 아니면 IDE 포트에 연결된 표준 드라이브를 사용하고 있습니까?

작업 빈도, 파일의 크기 및보고있는 파일 수에 따라 고려해야 할 기타 성능 문제가 있습니다. 기억해야 할 한 가지는 각 바이트 어레이가 쓰레기 수집기의 자비로 출시된다는 것입니다. 해당 데이터를 캐싱하지 않으면 많은 쓰레기를 만들고 대부분의 성능을 잃을 수 있습니다. GC의 % 시간. 청크가 85K보다 큰 경우, 모든 세대의 컬렉션이 자유 로워 지도록하는 큰 물체 힙 (LOH)에 할당 될 것입니다 (이것은 매우 비싸고 서버에서는 모든 실행이 진행되는 동안 모든 실행을 중지합니다. ). 또한, LOH에 많은 물체가있는 경우, LOH 조각화 (LOH는 절대 압축되지 않음)로 끝나면 성능 저하가 열악하고 기억이 나오지 않습니다. 특정 지점에 도달하면 프로세스를 재활용 할 수 있지만 이것이 모범 사례인지 모르겠습니다.

요점은, 모든 바이트를 메모리에 가장 빠른 방법으로 읽거나 전반적인 성능을 위해 단기 성능을 거래하기 전에 앱의 전체 수명주기를 고려해야한다는 것입니다.

말하고 싶습니다 BinaryReader 괜찮지 만 버퍼의 길이를 얻기위한 모든 코드 라인 대신에 이에 다시 활성화 될 수 있습니다.

public byte[] FileToByteArray(string fileName)
{
    byte[] fileData = null;

    using (FileStream fs = File.OpenRead(fileName)) 
    { 
        using (BinaryReader binaryReader = new BinaryReader(fs))
        {
            fileData = binaryReader.ReadBytes((int)fs.Length); 
        }
    }
    return fileData;
}

사용하는 것보다 낫습니다 .ReadAllBytes(), 내가 포함하는 최고 응답에 대한 의견에서 본 이후 .ReadAllBytes() 주석가 중 한 명이 파일> 600MB에 문제가 있었기 때문에 BinaryReader 이런 종류의 것을위한 것입니다. 또한, 그것을 넣습니다 using 진술은 FileStream 그리고 BinaryReader 닫히고 폐기됩니다.

'큰 파일'을 사용하는 경우 4GB 제한을 넘어서는 경우 다음 서면 코드 로직이 적절합니다. 주목해야 할 주요 문제는 Seek 방법에 사용되는 긴 데이터 유형입니다. 오랫동안 2^32 데이터 경계를 넘어서 지적 할 수 있습니다. 이 예에서 코드는 먼저 1GB의 청크로 큰 파일을 처리하는 것입니다. 큰 전체 1GB 청크가 처리 된 후 왼쪽 (<1GB) 바이트가 처리됩니다. 4GB 크기를 넘어서 파일의 CRC를 계산 하여이 코드를 사용합니다. (사용 https://crc32c.machinezoo.com/ 이 예에서 CRC32C 계산의 경우)

private uint Crc32CAlgorithmBigCrc(string fileName)
{
    uint hash = 0;
    byte[] buffer = null;
    FileInfo fileInfo = new FileInfo(fileName);
    long fileLength = fileInfo.Length;
    int blockSize = 1024000000;
    decimal div = fileLength / blockSize;
    int blocks = (int)Math.Floor(div);
    int restBytes = (int)(fileLength - (blocks * blockSize));
    long offsetFile = 0;
    uint interHash = 0;
    Crc32CAlgorithm Crc32CAlgorithm = new Crc32CAlgorithm();
    bool firstBlock = true;
    using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        buffer = new byte[blockSize];
        using (BinaryReader br = new BinaryReader(fs))
        {
            while (blocks > 0)
            {
                blocks -= 1;
                fs.Seek(offsetFile, SeekOrigin.Begin);
                buffer = br.ReadBytes(blockSize);
                if (firstBlock)
                {
                    firstBlock = false;
                    interHash = Crc32CAlgorithm.Compute(buffer);
                    hash = interHash;
                }
                else
                {
                    hash = Crc32CAlgorithm.Append(interHash, buffer);
                }
                offsetFile += blockSize;
            }
            if (restBytes > 0)
            {
                Array.Resize(ref buffer, restBytes);
                fs.Seek(offsetFile, SeekOrigin.Begin);
                buffer = br.ReadBytes(restBytes);
                hash = Crc32CAlgorithm.Append(interHash, buffer);
            }
            buffer = null;
        }
    }
    //MessageBox.Show(hash.ToString());
    //MessageBox.Show(hash.ToString("X"));
    return hash;
}

C#의 BufferedStream 클래스를 사용하여 성능을 향상시킵니다. 버퍼는 데이터를 캐시하는 데 사용되는 메모리의 바이트 블록으로 운영 체제에 대한 호출 수가 줄어 듭니다. 버퍼는 읽기 및 쓰기 성능을 향상시킵니다.

코드 예제 및 추가 설명은 다음을 참조하십시오.http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx

이것을 사용하십시오 :

 bytesRead = responseStream.ReadAsync(buffer, 0, Length).Result;

나는 시도하는 것이 좋습니다 Response.TransferFile() 방법 a Response.Flush() 그리고 Response.End() 큰 파일을 제공합니다.

2GB 이상의 파일을 다루는 경우 위의 방법이 실패 할 것입니다.

스트림을 나눠주는 것이 훨씬 쉽습니다. MD5 그리고 그것이 당신을 위해 당신의 파일을 청크 할 수 있도록하십시오.

private byte[] computeFileHash(string filename)
{
    MD5 md5 = MD5.Create();
    using (FileStream fs = new FileStream(filename, FileMode.Open))
    {
        byte[] hash = md5.ComputeHash(fs);
        return hash;
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top