The original office file is working with no problems (I tried word and excel), but when I upload the file to a database as binary and then download it from there to my PC and open the downloaded file, I get warning messages “excel found content cannot read” etc. and the file is getting plainer compared to the original file.
The exact error message is; “Excel found unreadable content in filename.xls. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes.”
How I upload the file:
'UPLOAD FILE
Dim fi As New FileInfo(FilePath)
Dim s As Stream = fi.OpenRead()
Dim buffer(fi.Length) As Byte 'I put the buffer in database in varbinary(max) format
s.Read(buffer, 0, fi.Length)
s.Close()
How I download and open the file:
'DOWNLOAD FILE
Dim fi As New FileInfo(FilePath)
Dim s As Stream = fi.OpenWrite()
Dim buffer As Byte() = reader("Binary")
s.Write(buffer, 0, buffer.Length)
s.Close()
'OPEN FILE
Dim p As New Process
p.StartInfo = New ProcessStartInfo(FilePath)
p.Start()
UPDATE:
As suggested, I tried simply copying the file, taking SQL completely out of the mix. Here is the code I tried, which also failed:
Private Sub CopyFile(ByVal filePath As String)
Dim fi As New FileInfo(filePath)
Dim s As Stream = fi.OpenRead()
Dim buffer(CType(fi.Length, Integer) - 1) As Byte
s.Read(buffer, 0, CType(fi.Length, Integer))
s.Close()
Dim fi2 As New FileInfo(filePath & " Copy")
Dim s2 As Stream = fi2.OpenWrite()
s2.Write(buffer, 0, buffer.Length)
s2.Close()
End Sub
As described by this MSDN article, VB.NET arrays are declared differently than in other languages, such as in C#. In other languages, when declaring a fixed-length array, the size given is used as the total length of the array. For instance, in c#, the statement
fixed byte buffer[3];would declare a byte array containing 3 elements (with indices 0 through 2). However, in VB, the size given when declaring a fixed array is used as the upper-bound for the array, not the size. Therefore, in VB, the statementDim buffer(3) As Bytedeclares a byte array containing 4 elements (with indices 0 through 3).With that in mind, if you look closely at your code, you are actually declaring a byte array which is one element larger than the size of the file (with indices 0 through fi.Length). You are then reading the entire file into the byte array, starting at index 0. Therefore, the last byte in the array is left as value 0 (a null character). You then write out the entire contents of the byte array to a new file, including that last null byte. Therefore, your code is correctly copying all the bytes in the file, but is adding an extra null byte to the end of it which makes Excel unhappy. If you look at the original file size and the file size of your newly created file, you will see that your new file is one byte larger than the original.
To fix this, you simply need to adjust the size of your array when you declare it so that it is exactly the same length as the file:
However, while I’m at it, I feel obliged to point out some other areas of improvement in the code that you posted. First of all, when using objects which implement the
IDisposableinterface, such asStream, it is best to use theUsingstatement whenever possible. Doing so ensures that the object is always properly closed/disposed, even in the event that an exception is encountered. For instance, it would be better if you did this:Also, it’s obvious that you are not using
Option Strictbecause if you were, you would not be allowed to use fi.Length (aLong) as an argument for the array size or for the buffer length. If you turn onOption Strict, you will be forced to explicitly state that you want to cast theLongvalue to anInteger. For instance:Turning on
Option Strictis a very good idea in most circumstances. It forces you to be aware of your variable types and when data may be lost. For instance, in this case, by havingOption Strictturned on, you become aware of the fact that the file size (Long.MaxValue) may be larger than the maximum length of an array (Integer.MaxValue), so, if you want to handle very large files, you would need to write a loop that reads and writes the file in chunks. Even if you don’t want to handle large files, it would be best to check the size first so you can handle the error gracefully rather than allowing an overflow exception to be thrown:Lastly, if you don’t care about handling large files, there is a simpler way to read and write all the bytes in the file: