关于不同数据库之间图像数据移植的心得和疑问

关于不同数据库之间图像数据移植的心得和疑问

最近由于工作需要,研究了下不同数据库之间的数据移植,尤其是图像数据的移植。

有些收获,也有些疑问,写下来还请大家指点。

文本信息的移植我就不多说了,主要说下图像数据的移植。

首先谈谈将mysql里的image数据移植到sybase下:

先看mysql.

当你用python获取一个image字段值的时候:

import MySQLdb

db = MySQLdb.connect('localhost','root','','testdb')
c = db.cursor()

c.execute("select imagerow from imagetable where imageid='xx'")
getimage = c.fetchone()

这个时候 getimage是个元组,但是如果取它的值的话:

getimage = getimage[0],然后你执行 type(getimage),python会告诉你这是一个array. ( 'array.array')
它的值类似于:

array('c', '\x02\xc2\x12\x00\x00\x01\x00\x00\x00\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xff\xff\xb4\xe7L:nKP@!\xc9m\'\xa1\xce\xbd;m\t\x8
\n\x85B\xe1\x16\xecw\x0b\xf8\xd3\xd8O\xdc-\xe5\x0f\\xff\'\xb9o\xf6\x98}\xdc\xad\xfe\x99\x90sy\x9d\xc7\
5Ec\x9e\xf1\xe0\x1e\x93\xae(z\xc7p9\\\xd0\xecmh\xdb ..... )

关于array模块,大家可以查看python自带的手册,有详细说明。

现在,我们来看获取sybase数据库的image字段:

import Sybase

db = Sybase.connect("database_server_name","user","pswd","testdb")
c = db.cursor()

c.execute("select imagerow from imagetable where imageid='xx'")
getimage = c.fetchone()

同样的,我们用type(getimage[0]),python告诉你这是一个'str'。
它的值类似于:
'bdm\xae]_\xf7y\x15\x98o<^m\xb9\xa1\xaa\x04"\x14\xa7\x1\x89\xe3H\xd8\x01\xe9\x813\xe4\xaf\xc3\xc0\x82\xc0\
x83d\x81\xb0\x91\xf7\x80|\xe9BG43\x9f\x82\xf2\xad\r\xeb\x  .... '

问题出来了:从mysql里弄出来的图像数据肯定要转换一下,否则即使你直接插到sybase里了,前台程序在读取这个图像的时候也会报错。

回到上面,从mysql里获取的图像给了getimage之后它是一个array,换个说法就是:getimage有array模块的属性。
array模块有个 'tostring()'方法,可以将array转换成一个字符串(机器码),那么,这就好办了,我们执行:

ss = getimage.tostring().这个时候,我们得到一个字符串,类似于从sybase里获取的图像文件的一个字符串。

如果这个时候把这个字符串直接插到数据库里是不可能的,仔细观察就会发现,这个字符串(可能用字符串不太合适)包含大量的 
有特殊含义的字符,直接插SQL 肯定报错。

这个时候又要用到array模块了。这也是我不理解的地方,还请前辈指教。

刚才我们得到的 ss 是array转换后的字符串,现在执行:

import array

ss = array.array('B',ss)

('B'代表int型。)

现在的ss是个列表,呵呵,python就这么神奇。它的值类似:

[40, 20, 10, 133, 66, 161, 80, 40, 20, 10, 133, 6 161, 80, 40, 20
,10, 133, 66, 161, 80, 40, 20,, 133, 191, 138, 250, 55, 85, 223,
15, 249, 95,91, 244, 31, 128, 50, 225, 2, 212, 127, 32, 226 ...]

然后: ss = array.array('B',ss).tostring()

又得到一个字符串~! 你可能会说我带你绕弯那,转来转去又转成字符串了。这也是我的疑问所在:

为什么从mysql里获取array后,使用tostring()方法得到的字符串不能直接插到sybase里,而使用
ss = array.array('B',ss)得到一个列表,然后把这个列表转换成一个字符串就可以了哪?
我对比过这两个字符串,并没有转义特殊字符。关于这一点,恳请前辈指教。

好了,现在我们可以把 ss = array.array('B',ss).tostring() 转换后的字符串插到sybase的imagerow里了:

c.execute("update imagetable set imagerow='%s'"%(ss))

但是每个数据库的特性也决定了写入图像数据的时候有不同的方法,如果对于mysql,这样做就可以了,
但是对与sybase,这样做其实并没有把数据真正写入,只写入了图像的基本信息。还需要用如下方法。

c.execute("select imagerow from imagetable where imageid='xx'")

r = c.getImageDesc(0)

c.writeImageData(r[0],ss)

如果返回1代表成功,0代表失败。

至此,从mysql里选择的图像数据才真正写入sybase里了。

这个脚本整理一下大概是这样:

import MySQLdb
import Sybase
import array

dbmysql = MySQLdb('localhost','root','','testdb')
dbsybase = Sybase('database_server_name','user','pswd','testdb')

my = dbmysql.cursor()
sy = dbsybase.cursor()

my.execute("select imagerow from imagetable where imageid='xx'")
b = my.fetchone()
b = b[0].tostring()
b = array.array('B',b)
ss = array.array('B',b).tostring()

sy.execute("update imagetable set imagerow='%s' where imageid='xx'"%(ss))
dbsybase.commit()

sy.execute("select imagerow from imagetable where imageid='xx'")
r = sy.getImageDesc(0)

sy.writeImageData(r[0],ss)






另外要说明几点:

要把一个图像数据写入mysql里的时候,要用MySQLdb.escape_string(ss) 把字符串的特殊字符转义掉。
关于这一点在《python cookbook》一书中有详细说明。 

如果你操作的是informix数据库,那么用select 语句查出来的图像数据是一个dbiRaw对象,你需要
str(dbiRaw)转换成字符串。

这些是我这几天的心得和疑问,如果有什么不对的地方恳请指点一二。
晕,怎么都没反应阿
加了精华了
谢谢斑竹~
因为没用过,所以没什么意见,呵呵。
没有用python作数据库操作的吗?一起探讨一下撒
我在把windows平台下的DBF文件转到NETBSD下的MYSQL下去,也碰到了一些问题.移植结束后看看有什么体会也来谈谈.


QUOTE:
原帖由 xie_minix 于 2006-10-23 14:43 发表
我在把windows平台下的DBF文件转到NETBSD下的MYSQL下去,也碰到了一些问题.移植结束后看看有什么体会也来谈谈.

好,期待中

另外有个问题要注意,如果你把图像数据读出来写成一个文件,那么处理特殊字符转换的问题会很麻烦的。

前段时间做了一个图像传输系统,数据库分别用了MYSQL和ORACLE的C API,发现他们之间都是直接将二进制编码保存在指定的存储区域,MYSQL直接用INSERT语句,把二进制编码作为一个字段值来插入数据库;在ORACLE中涉及到数据绑定,绑定好了之后,也是将二进制直接写入存储区。
所以我觉得在数据移植的时候是否也可以通过不转换数据,直接提取和存入二进制编码的方式来实现呢?
这种方式我觉得不会有什么数据丢失,而且数据多的话,效率应该不错,就是实现起来有点麻烦,需要调用数据库的API,C或者C++。
楼上说的有道理,可能是语言的差异吧,PYTHON把取出来的二进制数据当字符串来处理的,所以必须转换,因为这个字符串里包含了大量的对PYTHON来说具有特殊含义的字符。 C/C++我不熟,具体怎么实现我也不知道,不过如果直接调用数据库的API我想效率会比用PYTHON做的高