原始的office文件工作没有问题(我尝试了word和excel),但当我将文件以二进制形式上传到数据库,然后从那里下载到我的电脑并打开下载的文件时,我会收到警告消息"excel发现内容无法读取"等,与原始文件相比,文件变得更清晰了。
确切的错误消息为"Excel在filename.xls中发现无法读取的内容。是否恢复此工作簿的内容?如果您信任此工作簿的来源,请单击"是"。">
我如何上传文件:
'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()
我如何下载和打开文件:
'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()
更新:
按照建议,我尝试简单地复制文件,将SQL完全排除在外。这是我尝试过的代码,但也失败了:
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
如MSDN文章所述,VB.NET数组的声明与其他语言(如C#)不同。在其他语言中,当声明固定长度数组时,给定的大小被用作数组的总长度。例如,在c#中,语句fixed byte buffer[3];
将声明一个包含3个元素(索引为0到2)的字节数组。然而,在VB中,声明固定数组时给定的大小被用作数组的上限,而不是大小。因此,在VB中,语句Dim buffer(3) As Byte
声明了一个包含4个元素(索引为0到3)的字节数组。
考虑到这一点,如果你仔细查看你的代码,你实际上是在声明一个比文件大小大一个元素的字节数组(索引为0到fi.Length)。然后你将从索引0开始将整个文件读取到字节数组中。因此,数组中的最后一个字节保留为值0(空字符)。然后将字节数组的全部内容写入一个新文件,包括最后一个空字节。因此,您的代码正确地复制了文件中的所有字节,但在其末尾添加了一个额外的空字节,这让Excel很不满意。如果您查看原始文件大小和新建文件的文件大小,您会发现新文件比原始文件大一个字节。
要解决此问题,您只需在声明数组时调整数组的大小,使其与文件的长度完全相同:
Dim buffer(fi.Length - 1) As Byte
然而,当我在做这件事的时候,我觉得有必要指出您发布的代码中的其他一些改进领域。首先,当使用实现IDisposable
接口的对象(如Stream
)时,最好尽可能使用Using
语句。这样做可以确保对象始终正确关闭/释放,即使在遇到异常的情况下也是如此。例如,如果你这样做会更好:
Dim fi As New FileInfo(FilePath)
Using s As Stream = fi.OpenRead()
Dim buffer(fi.Length - 1) As Byte
s.Read(buffer, 0, fi.Length)
End Using
此外,很明显,您没有使用Option Strict
,因为如果您使用了,就不允许使用fi.Length(Long
)作为数组大小或缓冲区长度的参数。如果启用Option Strict
,您将被迫明确声明要将Long
值强制转换为Integer
。例如:
Dim fi As New FileInfo(FilePath)
Using s As Stream = fi.OpenRead()
Dim buffer(CInt(fi.Length) - 1) As Byte
s.Read(buffer, 0, CInt(fi.Length))
End Using
在大多数情况下,打开Option Strict
是一个非常好的主意。它迫使您注意变量类型以及数据何时可能丢失。例如,在这种情况下,通过打开Option Strict
,您会意识到文件大小(Long.MaxValue
)可能大于数组的最大长度(Integer.MaxValue
),因此,如果您想处理非常大的文件,则需要编写一个循环,以块的形式读取和写入文件。即使你不想处理大文件,最好先检查大小,这样你就可以优雅地处理错误,而不是允许抛出溢出异常:
If fi.Length >= Integer.Max Then
'Display or log error that the file is too large, and skip loading the file
Else
'Load file
End If
最后,如果你不关心处理大文件,有一种更简单的方法可以读取和写入文件中的所有字节:
'UPLOAD FILE
Dim buffer() As Byte = File.ReadAllBytes(filePath)
'DOWNLOAD FILE
Dim buffer As Byte() = reader("Binary")
File.WriteAllBytes(filePath, buffer)