Reading a dB blob field into a byte[]

otalado

New member
Joined
May 19, 2022
Messages
1
Programming Experience
Beginner
Platform: Windows 11 Pro x64, VS Studio 2019 Community x64, Mysql. I m trying to read a BLOB field into a byte array (.webp image to be later converted for PictureBox) . I ran into some issues with that. It compiles Ok but at run time it fails on the first rdr.GetBytes statement which I have marked in the code below:

code portion:
        public void showImage(int rowNr)
        {
            string fileName = rowitems[rowNr].pictName;
            int bufferSize = 1024;
            byte[] picture = new byte[bufferSize];
            long bytesRead, startIndex = 0;

            MySqlConnection conn = new MySqlConnection(connStr);

            MySqlCommand cmd = new MySqlCommand("SELECT PictureName FROM  Categories WHERE PictureName='?s';", conn);
            MySqlParameter picNameParam = new MySqlParameter("?picName", MySqlDbType.VarChar, 20);
            picNameParam.Value = fileName;
            cmd.Parameters.Add(picNameParam);

            conn.Open();
            MySqlDataReader rdr = cmd.ExecuteReader();
---->    bytesRead = rdr.GetBytes(0, startIndex, picture, 0, bufferSize);
            while (bytesRead == bufferSize)
            {
                startIndex += bufferSize;
                bytesRead = rdr.GetBytes(0, startIndex, picture, 0, bufferSize);
            }

            // convert  the picture byte array from a webp format to PictureBox bitmap
            Imazen.WebP.SimpleDecoder decoder = new Imazen.WebP.SimpleDecoder();
            var bitmap = decoder.DecodeFromBytes(picture, picture.Length);
            pictureBox1.Image = bitmap;
        }

The error triggered on the statement marked in code is: MySql.Data.MySqlClient.MySqlException: 'Invalid attempt to access a field before calling Read()' . I am afraid that I don't understand the cause of that error at all. I have used parametrized query, but I have temporarily removed it for sake of clarity. I searched on the web for a possible solution, but I have found that most of the examples are very similar or almost the same as what I am doing. Well, I don't doubt that the debugger is correct, but reading through the docs did not help me so far :(
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
The error is telling you exactly what is wrong. You need to call rdr.Read() first, even if you absolutely know that the query will return one and only row.

See the documentation for the base class of all database readers:
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
Once you fix that issue, your logic on lines 17-22 looks to be wrong. You seem to be reading 1KB chunks from the column, but you keep putting succeeding 1KB into the same location of your buffer. Shouldn't you be expanding the size of your buffer?

I suggest reading 1K chunks and append them into a memory stream, and then getting a flat array of bytes from the memory stream;

OR

Call GetBytes() passing in null first to get the total number of bytes you'll need for the image. Allocate a buffer that size, and call GetBytes() again with the buffer reference to get all the bytes in one go.
 

jay8anks

Member
Joined
May 6, 2022
Messages
19
Programming Experience
5-10
As a side note on this, I wasted some time a while back and part of my problem was I didn't actually store the image in the blob correctly to begin with.

There is an easy check in MySql Workbench:

Right click on the blob cell in the result grid and select "Open Value in Editor", which will show a new dialog where you can view the blob data, either as text, image or hex listing. Click on the image button. If you stored it correctly, you should be able to view the image.

May help someone...
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
The field already is a byte[], so just get the field value and cast it:
C#:
var data = (byte[])myDataReader[columnIndex];
Since .NET Framework 4.5 and .NET Core 1.0, you can also do this:
C#:
var data = myDataReader.GetFieldValue<byte[]>(columnIndex);
There's no point reading the data in chunks if you want to keep and combine all the chunks anyway. The point of reading chunks is it allows you to process and discard each chunk and thus keep overall memory usage down. If you're keeping all the chunks then you're using at least the same amount of memory and probably more.
 
Top Bottom