用RecordSet对象的 GetChunk/AppendChunk 方法
使用ADO GetChunk/AppendChunk 读写SQL Server BLOB字段
北京机械工业学院研00级 冉林仓 |
01-8-31 下午 12:07:48
|
在设计数据库的过程中,我们会经常要存储一些图形、长文本、多媒体(视频、音频文件)等各种各样的程序文件,如果我们在数据库中仅存储这些文件的路径信息,尽管这可以大大地减小数据库的大小,但是由于文件存在磁盘上,我们除了维护数据库外还要维护文件的路径信息,保持二者的一致,这对于我们管理数据库非常不方便。我们还是寄希望能够把这些文件的内容作为一个记录的一个字段值存到数据库中,这样文件的上传和下载就变成了简单的字段读写。我们不用再考虑这些文件是如何在磁盘上存储的,数据库会帮我们做好一切工作。 |
SQL Server提供了多达2GB字节的字段类型(TEXT、IMAGE、NTEXT),这么大的空间可以说对于我们保存一般的文件已经足够了,我们可以把需要保存的虚拟光驱映象文件、MP3、AutoCAD图形、精美图片、RealPlayer视频音频文件等的内容存入到数据库中,根据用户检索的信息,再把对应的记录读出来,存到本地硬盘的一个临时文件中,然后用其对应的程序打开它,利用这种方法,我们可以实现在一个局域网中实现客户端的信息共享,也可以用这种方法做一个简单的视频点播系统,或者做一个WEB上传下载程序。但是由于这些文件的内容不是简单的文本信息,我们无法通过一般的粘贴和复制把它们写进去或者读出来,那么我们怎么才能读写这些二进制大字段(Binary Large Objects, BLOB)呢? |
为了读写BLOB 字段,ADO为这些BLOB字段提供了两种方法GetChunk和AppendChunk,通过它们,你可以象读写文件一样,把其它文件的内容写进去读出来。 |
使用方法:variable = field.GetChunk( Size ) |
其中field为一个大文本或者二进制字段,size为要从该字段获得的字节或字符数。执行完将返回一个数据起始地址。由于系统限制,我们最好能够一部分一部分地从该字段获取数据,而不是整个把全部数据读出来。如果给定的size 大小大于该字段剩余没读出的的字节数,那么GetChunk仅返回剩余的数据;如果字段为空,将返回一个null值。 |
每一次顺序地调用GetChunk获取数据,都将从上一次读写没有读到的地方开始,然而如果你正从一个字段获取数据,然后又去设置或读取当前记录的另外一个字段,这样ADO就会认为你已经完成第一个字段的读取,如果你接着又读取第一个字段,ADO就会把这次调用视为一个新的GetChunk操作,将从数据的起始位置读写。如果你存取的是其它记录集对象,而且这个记录集不是第一个记录集的复制品,那么这个过程将不会打断GetChunk操作。 |
如果你想使用GetChunk方法读取一个字段,你必须把字段对象的Attributes属性的adFldLong位设置为真。如果你在一个没有当前记录的字段对象上使用GetChunk方法,将返回3021错误代码(没有当前记录)。 |
使用方法:object.AppendChunk Dataobject 为一个字段或参数对象。 |
Data 为一个包含数据变量,这些数据将被追加到对象中。 |
同上面一样,如果你的系统内存有限,你尽可能分多次把数据追加到字段或参数对象。 |
如果你想使用AppendChunk 方法写一个字段,你需要把字段对象的字段Attributes属性的adFldLong位设置为真,第一次对一个字段对象使用AppendChunk方法,将会覆盖任何已有数据,后面调用AppendChunk将会把数据追加到存在数据的尾部。在向一个字段追加数据的时候,如果你又去设置或读取当前记录的另一个字段的值,ADO会认为你已经完成了对第一个字段的追加,再次对第一个字段调用AppendChunk方法,会被ADO解释为一次新的操作,从而覆盖已有数据。如果你存取的是其它记录集对象,而且这个记录集不是第一个记录集的复制品,那么这个过程将不会打断AppendChunk操作。如果你在一个没有当前记录的字段对象上使用AppendChunk方法,将返回错误信息(没有当前记录)。 |
下面是实现读写文件的过程例子,它已经被应用到一个学生管理系统,用于各个部门发布内部通知,通知的内容可以来自声音文件,视频文件,或者WORD文档,网页或电子表格、幻灯片等等,通知发布后,将作为一个记录存到数据库中,每个部门都可以下载到本地,进行察看浏览。这种方法可以广泛地应用到ASP中,开发上传或下载程序用。 |
Const BLOCKSIZE As Long = 4096 |
Sub FileToColumn(Col As ADODB.Field, DiskFile As String) |
'col为一个ADO字段,DiskFile为一个文件名,它可以为一个远程文件。 |
Dim strData() As Byte '声明一个动态数组 |
Dim NumBlocks As Long '读写块数 |
Dim FileLength As Long '文件长度 |
Dim LeftOver As Long '剩余字节数 |
Dim SourceFile As Long ‘文件句柄 |
SourceFile = FreeFile '获得剩余的文件句柄号 |
Open DiskFile For Binary Access Read As SourceFile '以二进制读方式打开源文件。 |
FileLength = LOF(SourceFile) '获得文件长度 |
Peedy.Speak DiskFile & " Empty or Not Found." ‘调用Msagent控件,提示信息 |
NumBlocks = FileLength \ BLOCKSIZE ‘获得块数 |
LeftOver = FileLength Mod BLOCKSIZE ‘最后一块的字节数 |
Col.AppendChunk Null ‘追加空值,清除已有数据 |
ReDim strData(BLOCKSIZE) ‘从文件中读取内容并写到文件中。 |
Get SourceFile, , strData |
Get SourceFile, , strData |
2.从数据库中把文件内容读出来,并写到一个文件中。 |
Private Sub ColumnToFile(Col As ADODB.Field, DiskFile As String, rsset As Recordset) |
'从数据库获得数据并把它们写到硬盘上的一个临时文件中。 |
Dim NumBlocks As Long '注释见上文 |
If Not rsset.EOF And Not rsset.BOF Then |
If Len(Dir$(DiskFile)) > 0 Then |
Open DiskFile For Binary As DestFileNum |
NumBlocks = ColSize \ BLOCKSIZE |
LeftOver = ColSize Mod BLOCKSIZE |
strData = Col.GetChunk(BLOCKSIZE) |
Put DestFileNum, , strData |
strData = Col.GetChunk(LeftOver) |
Put DestFileNum, , strData |
只要在SQL Server2000中创建数据表时,设置字段类型为Image即可,浏览本地文件需调用ShellExecute函数。 |
ShellExecute Me.hWnd,”Open”,szFileName, 0, 0, SW_SHOWNORMAL |
本程序在Windows 2000环境下用Visual Basic 6和 SQL Server 2000 调试通过,采用的是Microsoft ADO Data Control 6.0控件。 | |