прочитать первые 10 МБ из файла с помощью c # - PullRequest
4 голосов
/ 05 ноября 2011

Мне нужно получить первые 10 МБ файла и вычислить md5 из этого, как я могу добиться этого?Я не могу найти образец для чтения фрагмента файла.У меня есть что-то вроде этого:

FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();

StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
     sb.Append(retVal[i].ToString("x2"));
}
var md5Final = sb.ToString();

Но он читает весь файл.

Ответы [ 6 ]

8 голосов
/ 05 ноября 2011

Вы можете прочитать файл порциями и передать его MD5CryptoServiceProvider порциями, используя TransformBlock.Таким образом, вам не нужно использовать 10 МБ памяти для буфера.Пример:

long read = 0;
int r = -1; 
const long bytesToRead = 10 * 1024 * 1024;
const int bufferSize = 10*1024;
byte[] buffer = new byte[bufferSize];
MD5 md5 = new MD5CryptoServiceProvider();
using(var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read) )
{
    while(read <= bytesToRead && r != 0) 
    {
        read += (r = stream.Read(buffer, 0, bufferSize));
        md5.TransformBlock(buffer, 0, r, null, 0);
    }
}
md5.TransformFinalBlock(buffer, 0,0);
string md5Final = String.Join("", md5.Hash.Select(x => x.ToString("x2")));
3 голосов
/ 05 ноября 2011

Чтобы прочитать часть файла, используя маленькие куски, вы можете попробовать:

public byte[] ReadPart(Stream stream)
{
    byte[] buffer = new byte[1024];
    int read=0;

    int chunk;
    while ( (chunk = stream.Read(buffer, read, buffer.Length-read)) > 0)
    {
        read += chunk;
        if (read == buffer.Length && read < 10*1024*1024) // 10MB
        {
            int nextByte = stream.ReadByte();
            if (nextByte==-1)
            {
                return buffer;
            }

            byte[] newBuffer = new byte[buffer.Length*2];
            Array.Copy(buffer, newBuffer, buffer.Length);
            newBuffer[read] = (byte)nextByte;
            buffer = newBuffer;
            read++;
        }
    }
    // Buffer is now too big. Shrink it.
    byte[] ret = new byte[read];
    Array.Copy(buffer, ret, read);
    return ret;
}

и затем вычислить MD5 для этого массива ...

2 голосов
/ 05 ноября 2011
  var bytes = new byte[10000000]; // Or 10*1024*1024 according to your def of a MB
  int realLength;

  using (var file = new FileStream(filename, FileMode.Open))
  {
    realLength = file.Read(bytes, 0, bytes.Length);
    // The file may be shorter than expected.
  }

  var md5 = new MD5CryptoServiceProvider();
  byte[] hash = md5.ComputeHash(bytes, 0, realLength); 

Должен признать, что выделение 10 МБ может оказаться не самым элегантным решением.Я написал это с 10 КБ вместо 10 МБ в памяти.YMMV.

0 голосов
/ 05 ноября 2011

Вы можете реализовать класс Stream, который ограничивает длину базового Stream объекта (FileStream в вашем случае) :

public class LengthLimitedStream : Stream
{
    private Stream baseStream;
    private long maxLength;

    public LengthLimitedStream(Stream stream, long maxLength)
    {
        if (stream.Position > maxLength) { throw new IOException(); }

        this.baseStream = stream;
        this.maxLength = maxLength;
    }

    public override bool CanRead
    {
        get { return this.baseStream.CanRead; }
    }

    public override long Length
    {
        get { return Math.Min(this.maxLength, this.baseStream.Length); }
    }

    public override long Position
    {
        get
        {
            return this.baseStream.Position;
        }
        set
        {
            if (value > maxLength)
            {
                throw new IOException();
            }

            this.baseStream.Position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        if (this.Position + offset + count > this.maxLength)
        {
            count = (int)(this.maxLength - (this.Position + offset));
        }

        return this.baseStream.Read(buffer, offset, count);
    }

    // Lots of stuff omitted you may want to implement but not important in this case ...
}

(Добавьте валидацию параметров и тому подобное, но вы поймете идею)

Таким образом, вы все равно можете использовать метод ComputeHash(Stream), и он выглядит чистым и простым (вмое мнение) .

0 голосов
/ 05 ноября 2011

Как насчет преобразования файла в байтовый массив, чтобы вы могли перебирать первые 10 МБ. Чтобы получить байтовый массив =>

private byte [] StreamFile(string filename)
{ 
FileStream fs = new FileStream(filename, FileMode.Open,FileAccess.Read); 

// Create a byte array of file stream length 
 byte[] fileData = new byte[fs.Length]; 

//Read block of bytes from stream into the byte array 
fs.Read(fileData,0,System.Convert.ToInt32(fs.Length)); 

//Close the File Stream 
fs.Close(); 

return fileData; //return the byte data
}

После этого я просто перебираю fileData, беру 10 первых МБ и делаю MD5

0 голосов
/ 05 ноября 2011

Вы можете прочитать первые 10 Мбайт в байт [], а затем дать ComputeHash экземпляр MemoryStream, поддерживаемый байтом [].

...