如何读取Access中OLE对象字段中的图片
分类: 代码, 笔记 | 标签: Access, ole, 数据库 | 日期:2008-09-15 | 1 views
由于直接在Microsoft Access中插入OLE对象时,会自动的用封包的形式插入所选对象,因此对于需要SQL返回图像等格式的时候如果直接调用原始的数据会出错. 微软没有给出Package的格式,也没有相关的控件可以提供Package的解包操作.
无奈为了先天下之忧而忧,只好拿起Winhex对这个烂包下手.
下表是它的头部16进制数据
| 15 | 1C | 24 | 00 | 02 | 00 | 00 | 00 | 08 | 00 | 08 | 00 | 14 | 00 | 1C | 00 |
| FF | FF | FF | FF | 50 | 61 | 63 | 6B | 61 | 67 | 65 | 00 | 50 | 61 | 63 | 6B |
| 61 | 67 | 65 | 00 | 01 | 05 | 00 | 00 | 02 | 00 | 00 | 00 | 08 | 00 | 00 | 00 |
| 50 | 61 | 63 | 6B | 61 | 67 | 65 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| B5 | 79 | 01 | 00 | 02 | 00 | 69 | 6D | 61 | 67 | 65 | 38 | 37 | 2E | 6A | 70 |
| 67 | 00 | 48 | 3A | 5C | 64 | 6F | 63 | 75 | 6D | 65 | 6E | 74 | 73 | 5C | 69 |
| 6D | 61 | 67 | 65 | 38 | 37 | 2E | 6A | 70 | 67 | 00 | 00 | 00 | 03 | 00 | 14 |
| 00 | 00 | 00 | 48 | 3A | 5C | 54 | 65 | 6D | 70 | 5C | 69 | 6D | 61 | 67 | 65 |
| 38 | 37 | 2E | 6A | 70 | 67 | 00 | F6 | 78 | 01 | 00 | FF | D8 | FF | E0 | 00 |
| 10 | 4A | 46 | 49 | 46 | 00 | 01 | 02 | 00 | 00 | 64 | 00 | 64 | 00 | 00 | FF |
开头的15 1C 表示封包开头.我这里是拿图片文件做实验,所有的图片的包都测试通过.
所有的Package的内容部分均从偏移量0X40开始,也就是offset=64的位置.即上表第五行
第五行开头四个bit,由低位到高位表示Package内容的大小,本例的大小为0179B5,即96653字节.
之后的02表示偏移2位开始读取文件名和文件全路径,中间以00隔开.
读完之后连续几个00之后出现03 00 14的数值.想来03大概是14位置之后偏移3位开始读取,读取的长度为十六进制的14,也就是20位.本例中这20位读出来的字符串是”H:Tempimage87.jpg “.不包含引号.其中20位字符最后一个是00为标志的结束符号.也就是C语言中的”".
紧接着的4个比特表示Package正文的大小,也就是我们当初插入的文件本身的大小.本例中的大小是0178F6,也就是96502字节.四个比特所能表示的最大大小约为3.9GB.相信所有能够直接插入数据库的文件大小都包含在内了.
接下来就是正文了,FF D8 FF E0 …………… 本例中的文件是一个标题为image87的JPEG文件,FF D8 FF正是jpg文件的标头.因此分析的结果应该是正确的.从FF D8 FF开始读取96502个数值(包括FF D8 FF),所得到的就是所需要的文件.
updated @22:43 最后再加上解图片包的方法,语言是VB.net.需要导入System.IO.此函数返回的IOMemoryStreaming对象可以直接使用PictureBox.Image=Image.FromStream()来读入图像
Public Function GetPackageContent(ByVal bytes As Array) As MemoryStream
Dim by As System.IO.MemoryStream = New System.IO.MemoryStream()
If Not (bytes(0) = 21 And bytes(1) = 28) Then
by.Write(bytes, 0, bytes.Length)
Return by
End If
Dim bt As Array = New Int32() {}
Dim offset As Integer = 64, zerocount As Integer = 0
Dim j As Integer = offset + 3
While j < bytes.Length - 1
If bytes(j) = 0 Then
zerocount = zerocount + 1
End If
j = j + 1
If zerocount = 11 Then
Exit While
End If
End While
Dim k As Integer = bytes(j) + (bytes(j + 1) + (bytes(j + 2) + bytes(j + 3) * 256) * 256) * 256
by.Write(bytes, j + 4, k)
Return by
End Function
也许你还对这篇文章感兴趣:如何读取和存储Access数据库中的OLE对象

非常感谢您的代码,但是我使用的时候还是无法从Access中读取图片数据。
我存图片的时候使用的是memoryStream.GetBuffer将图片转换为byte(),读取的时候一样会报错。郁闷中啊
[回复]
star @ 2010年07月27日
@star, 请你参看如何读取和存储Access数据库中的OLE对象一文
[回复]
lx @ 2010年07月27日