I've been writing and reading PDF's to a SQL Server 2008 FileStream for a few months now without any major problems (apart from tedious user permissions). Yesterday I had a user inform me that some of their PDF's were being corrupted after being written into the FileStream. So, I did some debugging and I found the problem, but it appears to be a bug with the SqlFileStream libraries that write the file to the FileStream.
Here is my code that writes to the FileStream:
// Byte array representing the FileStream
byte[] fsBytes = (byte[])obj;
SqlFileStream sqlFS = new SqlFileStream(path, fsBytes, FileAccess.Write);
byte[] b = new byte[4096];
int read;
stream.Seek(0, SeekOrigin.Begin);
while ((read = stream.Read(b, 0, b.Length)) > 0) {
sqlFS.Write(b, 0, read);
}
sqlFS.Close();
From my debugging, I determined that the last iteration reading from the stream has a read value equal to 1253, which means that the last stream read has data in the byte array from index 0 to 1252, and this is correct. Everything at and after 1253 is from the previous read.
So, my understanding is that sqlFS.Write(b, 0, 1253) will write everything from index 0 to 1252 of the byte array into the SqlFileStream. However, it is actually writing everything in the byte array to the SqlFileStream. I have verified this by pulling the PDF back out of the database, and even though I can't view it normally since its now corrupted, I can still open it in a text editor and view the garbal at the end of it that doesn't belong there (all of the data that was at position 1253 and after).
I am doing something wrong here, or does the SqlFileStream Write method have a bug like I think it does?
What is odd is that I've uploaded quite a few other PDF's and text files and images and I've never seen this problem. I have no idea why it is occurring with some PDF's and not others...
EDIT: Here is the code for my read method. The bug may be here as well (thanks to Remus for pointing this out!).
SqlFileStream objSqlFileStream = new SqlFileStream(path, objContext, FileAccess.Read);
objSqlFileStream.Seek(0, SeekOrigin.Begin);
b = new byte[4096];
int read;
while ((read = objSqlFileStream.Read(b, 0, b.Length)) > 0) {
Response.BinaryWrite(b);
}
objSqlFileStream.Close();
EDIT #2 (fixed code):
SqlFileStream objSqlFileStream = new SqlFileStream(path, objContext, FileAccess.Read);
objSqlFileStream.Seek(0, SeekOrigin.Begin);
b = new byte[4096];
int read;
while ((read = objSqlFileStream.Read(b, 0, b.Length)) > 0) {
if (read < 4096) {
byte[] b2 = new byte[read];
System.Buffer.BlockCopy(b, 0, b2, 0, read);
Response.BinaryWrite(b2);
}
else
Response.BinaryWrite(b);
}
objSqlFileStream.Close();