Because of the remoteness of SQL Azure it is beneficial to have some tricks in your coding toolbox for dealing with large binary objects, the varbinary(max) data type in SQL Azure. One of these is to be able to stream large binary objects (BLOB) -- reading or writing a piece of the data at a time.
This article provides a SqlStream class written in C# code. The class implements the abstract Stream class for the varbinary(max) data type on SQL Azure; Stream is an abstract class defined in the .NET CLR that is well supported and very versatile. The SqlStream class provided when used with SQL Azure allows you to manipulate a single blob a chunk at a time.
Using the SqlStream class provided you can:
The blog post is a start of a series, in the coming days we will build some of the applications listed above. For now, here are some samples for using the SqlStream class. Download the SqlStream class its own .cs file at the bottom of the post.
The first sample uses the SqlStream class to read an image from the Adventure Works database deployed on SQL Azure and saving it to a file. You can download the Adventure Works database from SQL Server Database Samples.
using (SqlConnection sqlConnection = new SqlConnection( "Server=tcp:yourServer.database.windows.net;" + "Database=AdventureWorksLTAZ2008R2;" + "User ID=yourLogin@yourServer;Password=yourPassword;" + "Trusted_Connection=False;Encrypt=True;")) { sqlConnection.Open(); using (SqlStream sqlStream = new SqlStream( sqlConnection, "SalesLT", "Product", "ThumbNailPhoto", "ProductID", SqlDbType.Int, 884)) { Byte[] buffer = new Byte[1024]; Int32 read = 0; using (BinaryReader binaryReader = new BinaryReader(sqlStream)) { using (FileStream fileStream = new FileStream( "c:\\temp\\image.jpg", FileMode.Create)) { using (BinaryWriter binaryWriter = new BinaryWriter(fileStream)) { do { read = binaryReader.Read(buffer, 0, 1024); binaryWriter.Write(buffer, 0, read); } while (read > 0); } } } } }
This sample uses the SqlStream class to write the data in a file to a varbinary(max) column defined in out Adventure Works database deployed on SQL Azure.
using (SqlConnection sqlConnection = new SqlConnection( "Server=tcp:yourServer.database.windows.net;" + "Database=AdventureWorksLTAZ2008R2;" + "User ID=yourLogin@yourServer;Password=yourPassword;" + "Trusted_Connection=False;Encrypt=True;")) { sqlConnection.Open(); using (SqlStream sqlStream = new SqlStream(sqlConnection, "SalesLT", "Product", "ThumbNailPhoto", "ProductID", SqlDbType.Int, 884)) { Byte[] buffer = new Byte[1024]; Int32 read = 0; using (BinaryWriter binaryWriter = new BinaryWriter(sqlStream)) { using (FileStream fileStream = new FileStream( "c:\\temp\\image.jpg", FileMode.Open)) { using (BinaryReader binaryReader = new BinaryReader(fileStream)) { do { read = binaryReader.Read(buffer, 0, 1024); binaryWriter.Write(buffer, 0, read); } while (read > 0); } } } } }
Do you have questions, concerns, comments? Post them below and we will try to address them.
Dear Wayne,
I think there's a little bug in the SqlStream class. In the Seek method, there are tests to check wether the offset is in range. But you use and && operator instead of ||. The if statement "if ((offset < 0) && (offset > this.Length))" will always fail if length > 0.
Greetings,
Michiel Vos