读取文件然后将文件写入 SQL Server BLOB 列的代码,生成具有不同字节的文件
Posted
技术标签:
【中文标题】读取文件然后将文件写入 SQL Server BLOB 列的代码,生成具有不同字节的文件【英文标题】:Code to read and then write a file into a SQL Server BLOB column producing files with different bytes 【发布时间】:2017-01-29 11:34:12 【问题描述】:使用:
MS-SQL Server 2014 MS-Access 2013 带有链接到 SQL 的 ODBC 表 服务器数据库 “SQL Server”ODBC 驱动程序(10.00.10586.00,Microsoft 公司,SQLSRV32.DLL) 道我们有一个 Access 数据库,其中将 ODBC 表链接到 SQL Server 2014 数据库,在 Access 应用程序中的表单后面使用 VBA 代码将文件上传到 SQL Server blob (varbinary[max]) 列,然后下载来自同一 blob 列的文件。
但是我们发现,在检索之前从 blob 列上传的文件时,保存的文件在文件末尾添加了一些额外的字节。
Beyond Compare 中两个文件的比较屏幕截图如下:
如果有人可以检查并指出代码中的错误,我将不胜感激。代码如下:
Function ReadBLOB(SourceFileName As String, TableName As String, FieldName As String, _
IDFieldName As String, IDFieldValue As Variant)
Dim NumBlocks As Integer, SourceFile As Integer, i As Integer
Dim FileLength As Long
Dim LeftOver As Long
Dim FileData() As Byte
Dim RetVal As Variant
Dim BlockSize As Long
Dim s As String
On Error GoTo Err_ReadBLOB
BlockSize = 32767
' Open the source file.
SourceFile = FreeFile
Open SourceFileName For Binary Access Read As SourceFile
' Get the length of the file.
FileLength = LOF(SourceFile)
If FileLength = 0 Then
ReadBLOB = 0
Exit Function
End If
' Calculate the number of blocks to read and leftover bytes.
NumBlocks = FileLength \ BlockSize
LeftOver = FileLength Mod BlockSize
Dim T As dao.Recordset
If TypeName(IDFieldValue) = "String" Then
IDFieldValue = "'" & IDFieldValue & "'"
End If
s = "SELECT [" & FieldName & "] FROM [" & TableName & "] WHERE [" & IDFieldName & "] = " & IDFieldValue
Set T = CurrentDb.OpenRecordset(s, dbOpenDynaset, dbSeeChanges)
T.Edit
' Read the 1st block of data (upto Leftover in size), writing it to the table.
'FileData = String$(LeftOver, 32)
ReDim FileData(LeftOver)
Get SourceFile, , FileData
T(FieldName).AppendChunk (FileData)
' Read the remaining blocks of data, writing them to the table.
'FileData = String$(BlockSize, 32)
ReDim FileData(BlockSize)
For i = 1 To NumBlocks
Get SourceFile, , FileData
T(FieldName).AppendChunk (FileData)
Next i
' Update the record and terminate function.
T.Update
Close SourceFile
ReadBLOB = FileLength
Exit Function
Err_ReadBLOB:
ReadBLOB = -Err
MsgBox Err.Description
Exit Function
End Function
Function WriteBLOB2(TableName As String, FieldName As String, IDFieldName As String, _
IDFieldValue As Variant, DestinationFileName As String) As Long
Dim NumBlocks As Integer, DestFile As Integer, i As Integer
Dim FileLength As Long, LeftOver As Long
Dim FileData() As Byte
Dim RetVal As Variant
Dim BlockSize As Long
Dim s As String
Dim f As String
On Error GoTo Err_WriteBLOB
BlockSize = 32767
Dim T As dao.Recordset
If TypeName(IDFieldValue) = "String" Then
IDFieldValue = "'" & IDFieldValue & "'"
End If
s = "SELECT [" & FieldName & "] FROM [" & TableName & "] WHERE [" & IDFieldName & "] = " & IDFieldValue
Set T = CurrentDb.OpenRecordset(s, dbOpenSnapshot, dbSeeChanges)
If T.RecordCount = 0 Then
WriteBLOB2 = 0
Exit Function
End If
' Get the size of the field.
FileLength = T(FieldName).FieldSize()
If FileLength = 0 Then
WriteBLOB2 = 0
Exit Function
End If
' Calculate number of blocks to write and leftover bytes.
NumBlocks = FileLength \ BlockSize
LeftOver = FileLength Mod BlockSize
' Remove any existing destination file.
DestFile = FreeFile
Open DestinationFileName For Output As DestFile
Close DestFile
' Open the destination file.
Open DestinationFileName For Binary As DestFile
' Write the leftover data to the output file.
FileData = T(FieldName).GetChunk(0, LeftOver)
Put DestFile, , FileData
' Write the remaining blocks of data to the output file.
For i = 1 To NumBlocks
' Reads a chunk and writes it to output file.
FileData = T(FieldName).GetChunk((i - 1) * BlockSize + LeftOver, BlockSize)
Put DestFile, , FileData
Next i
' Terminates function
Close DestFile
WriteBLOB2 = FileLength
Exit Function
Err_WriteBLOB:
WriteBLOB2 = -Err
MsgBox Err.Description
Exit Function
End Function
Public Sub ClearSQLBlob2(TableName As String, FieldName As String, _
IDFieldName As String, IDFieldValue As Variant)
If TypeName(IDFieldValue) = "String" Then
IDFieldValue = "'" & IDFieldValue & "'"
End If
DoCmd.SetWarnings False
DoCmd.RunSQL "UPDATE [" & TableName & "] SET [" & FieldName & "] = NULL WHERE [" & IDFieldName & "] = " & IDFieldValue
DoCmd.SetWarnings True
End Sub
【问题讨论】:
这将有助于从您的问题中删除所有非必要代码,尤其是所有那些SysCmd
电话。
您是否 100% 确定 blob 列中的值包含原始数据?还是在上传过程中数据已经损坏?最后附加了哪些值?
@erg:文件在上传过程中损坏。我通过使用 blob 编辑器程序从数据库下载原始文件进行了检查。但这就是我问这个问题的原因。
【参考方案1】:
我认为问题是:
除非您的模块中有 Option Base 1
声明,否则数组是从零开始的。
所以如果例如LeftOver
= 2,
ReDim FileData(LeftOver)
实际上会声明一个数组FileData(0 To 2)
,它包含3个字节。所以下面的Get
将读取 3 个字节,但您希望它读取 2 个字节。
全尺寸数组也是如此。
最后你从文件中读取了太多NumBlocks + 1
字节,剩下的将是00
字节。
解决方案:使用
ReDim FileData(1 To LeftOver)
ReDim FileData(1 To BlockSize)
编辑:请注意,您必须检查LeftOver = 0
的情况。
【讨论】:
以上是关于读取文件然后将文件写入 SQL Server BLOB 列的代码,生成具有不同字节的文件的主要内容,如果未能解决你的问题,请参考以下文章
AWS Glue - 从 sql server 表中读取并作为自定义 CSV 文件写入 S3
PB语言如何解析一个以TAB分割的文本文件,并把文件内容读取到SQL Server数据库中? 希望能给出代码,谢谢
在将新文件主动写入源目录时,如何安全地将文件导入 ssis 中的 sql server?