Прочитать первые 10 МБ из файла с помощью C#
Мне нужно получить первые 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 ответов
Вы можете прочитать файл порциями и передать его 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")));
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.
Чтобы прочитать часть файла, используя маленькие куски, вы можете попробовать:
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 на этом массиве...
Вы можете прочитать первые 10 Мбайт в байт [], а затем дать ComputeHash экземпляр MemoryStream, поддерживаемый байтом [].
Вы могли бы реализовать 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)
метод и выглядит чисто и просто (на мой взгляд).
Как насчет преобразования файла в байтовый массив, чтобы вы могли перебрать первые 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