Home > OS >  Converting a memory stream to an array but taking only a specified number of elements
Converting a memory stream to an array but taking only a specified number of elements

Time:10-28

I'm interested in implementing image format validation. I'm taking an input file (as IFormFile), and I want to encode it to bytes, and to compare these bytes to the starting bytes of formats such as jpeg and png. If the file's first two bytes equal to those of jpeg, for example, then the file is a jpeg image.

The implementation attached converts the entire file to an array of bytes, which seems to be inefficient:

        using var stream = new MemoryStream();
        file.CopyTo(stream);
        byte[] checkIfImage = stream.ToArray();

Then, we'll compare it to bytes of jpeg or png.

        var png = new byte[] { 137, 80 };
        var jpeg = new byte[] { 255, 216 };

Rather than creating this big inefficient array containing all of the file's bytes, I want to create an array containing only the first two bytes, so the comparison will be efficient. However, I cannot simply add .Take(2) or something like that after .ToArray().

What should I do?

Thanks!

CodePudding user response:

Disregarding any other problems you have conceptually or otherwise... Since you are allocating for the MemoryStream, you might as well just use GetBuffer to access to the underlying array. From there you can use any comparison technique you like.

In this example i'm using Memory<T> and ReadOnlyMemory<T> and using SequenceEqual to check for the pattern (¯\_(ツ)_/¯)

Given

private static readonly (string Name, ReadOnlyMemory<byte> Pattern)[] _patterns =
{
   ("png", new byte[] {1, 2}),
   ("jpj", new byte[] {1, 216}),
};

Usage

using var file = new MemoryStream(new byte[] {1, 2, 3, 4, 5});
using var stream = new MemoryStream();
file.CopyTo(stream);

var mem = stream.GetBuffer().AsMemory();

foreach (var (name, pattern) in _patterns) 
   if (pattern.Span.SequenceEqual(mem.Span(0,pattern.Span.Length)))
      Console.WriteLine("Found : "   name   ", "   Convert.ToHexString(pattern.Span));

Output

Found : png, 0102

Disclaimer 1 : If you are using the old and busted .net framework, all bets are off. You will need to do this with arrays and crayons

Disclaimer 2 : This was not meant to be the greatest code in the world, it was just a tribute

CodePudding user response:

Just use the stream.Read method

var firstBytes = new byte[2];
var nrBytesRead = filestream.Read(firstBytes);
if(nrBytesRead == firstBytes.Length){
    // do the comparison
}

Classes like binaryreader might also be useful. Reading the entire stream to memory can be convenient, but should in general be avoided if performance or memory usage is a concern.

  • Related