将Gtk.Textbuffer存储在SQL数据库中。编码麻烦

时间:2018-11-13 23:18:56

标签: python sql character-encoding gtk glade

我正在使用 python2 / Gtk3 / Glade 开发一个笔记应用程序。

这些注释存储在MySQL数据库中,并显示在TextView widget中。 我可以加载/存储/显示纯文本格式。但是我希望能够将图像添加到注释页面,并将其存储在数据库中。因此必须对数据进行序列化,并且在弄清楚如何对序列化的序列进行编码/解码时遇到了一些麻烦数据进出数据库。我收到Unicode起始字节错误。如果正在处理文件,则可以以二进制模式打开文件,但是我将其作为字符串存储在数据库中。我已经尝试过使用bytes()string.encode() [参见下面的示例代码]和其他几种方法将 encoding / decoding 作为UTF-8和ASCII格式,但没有其他效果。

我正在使用此功能将图像添加到textview缓冲区中:

def _AddImagetoNode(self,oWidget):
    filenm = None
    seliter = self.GetTreeSelection(self.treeview)
    filenm = self.FileOpenDiag("Select an Image To Insert.","Image","*.png,*.jpg,*.bmp")
    if filenm == None:
        return()

    #filenm =  "/home/drift/Pictures/a.png"
    buf = self.dataview.get_buffer()
    pixbuf = GdkPixbuf.Pixbuf.new_from_file(filenm)
    #pixbuf.scale_simple(dest_width, dest_height, gtk.gdk.INTERP_BILINEAR)
    buf.insert_pixbuf(buf.get_end_iter(), pixbuf) 
    self.dataview.set_buffer(buf)
    self.dataview.show()

这是存储textview缓冲区的函数:

def SaveDataView(self):
    global DataViewNode
    global DataViewIsImage

    if len(self.GetProjectName()) == 0:
        return()
    buf = self.dataview.get_buffer()

    format = buf.register_serialize_tagset()
    data2 = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

    #convert bytes(data) to string
    data = data2.decode(encoding='UTF-8') #<< i think my problem is here
    print("save b4 decode >>>>>>:%s"%data2)

    sql = "UPDATE " + self.GetProjectName() + " SET tDataPath=%s  WHERE tNodeID=%s"
    val = (data, DataViewNode)

    self.cursor.execute(sql,val)
    self.mariadb_connection.commit()

这是加载缓冲区的函数:

def UpdateDataView(self, nodeid):
    global DataViewNode
    #global DataViewIsFile
    DataViewNode=nodeid


    if self.GetProjectName() != None and DataViewNode != None:
        self.dataview.set_sensitive(True)
    else:
        self.dataview.set_sensitive(False)
        self.dataview.show()
        return()

    buf = self.dataview.get_buffer()
    buf.set_text('')
    enc = self.DbGetNodeData(nodeid)



    #convert string(enc) to bytes
    data = enc.encode(encoding='UTF-8')#<<< i think my problem is here
    print("update after decode >>>>>>>>>: %s"%data)
    ########### load
    format = buf.register_deserialize_tagset()
    buf.deserialize(buf, format, buf.get_end_iter(),data) 


    #buf.set_text(enc)
    self.dataview.set_buffer(buf)
    self.dataview.show()

我正在使用mysql.connector连接到mariadb。 这是sql连接字符串:

self.mariadb_connection = mariadb.connect(user='box', password='box', host='localhost', database='Boxer',charset='utf8')

这是我遇到的错误。

  

回溯(最近一次通话最后一次):文件“ Boxer.py”,第402行,在   _TreeSelectionChanged       self.SaveDataView()文件SaveBoxView中的“ Boxer.py”文件,第334行       data = data2.decode(encoding ='UTF-8')UnicodeDecodeError:'utf-8'编解码器无法解码位置174的字节0xb4:无效的起始字节   追溯(最近一次通话):文件“ Boxer.py”,行398,在   _DataViewLostFocus       self.SaveDataView()文件SaveBoxView中的“ Boxer.py”文件,第334行       data = data2.decode(encoding ='UTF-8')UnicodeDecodeError:'utf-8'编解码器无法解码位置174的字节0xb4:无效的起始字节

使用此代码,我可以在文本视图中添加/编辑纯文本并成功保存/加载,但是一旦添加图像,我就可以编码错误。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

这是一个更完整的示例:

def example (self):

        #retrieve info from first textview
        buf = self.builder.get_object('textbuffer1')
        format = buf.register_serialize_tagset()
        data = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

        #run db update to prove it can be inserted into a database
        db = psycopg2.connect(database= 'silrep_restore3', host='192.168.0.101', 
                                        user='postgres', password = 'true', 
                                        port = '5432')
        c = db.cursor()
        c.execute("UPDATE products SET byt = %s WHERE id = 1", (psycopg2.Binary(data),))

        #append info to second treeview as a proof of concept
        c.execute("SELECT byt FROM products WHERE id = 1")
        data = c.fetchone()[0]

        buf = self.builder.get_object('textbuffer2')
        format = buf.register_deserialize_tagset()
        buf.deserialize(buf, format, buf.get_end_iter(), data)

由于您使用的是MySQL,因此建议您阅读本article,以了解有关插入和检索数据的信息。

在我的示例中,我使用了一个bytea列。在MySQL中,这可能是BLOB或BINARY类型。

P.S。对不起,我的回答中没有完整的MySQL示例。我本来会发表评论,但是评论对于正确的格式是可悲的。

答案 1 :(得分:0)

得到它的效果。感谢theGtknerd,您的答案才是关键。对于任何对此有麻烦的人,我最终都将BLOB类型用于与该列一起工作的MySQL字段类型。我尝试使用BINARY [返回格式错误的序列化数据]和VARBINARY [甚至不允许我创建表],所以我最终使用了LONGBLOB类型。 这是任何需要它的人的工作代码。

def UpdateDataView(self, nodeid):
    global DataViewNode
    #global DataViewIsFile
    DataViewNode=nodeid


    if self.GetProjectName() != None and DataViewNode != None:
        self.dataview.set_sensitive(True)
    else:
        self.dataview.set_sensitive(False)
        self.dataview.show()
        return()

    buf = self.dataview.get_buffer()
    buf.set_text('')
    data = self.DbGetNodeData(nodeid)
    if data =='':
        return()


    format = buf.register_deserialize_tagset()
    buf.deserialize(buf, format, buf.get_end_iter(),data)       

    self.dataview.set_buffer(buf)
    self.dataview.show() 


def SaveDataView(self):
    global DataViewNode
    global DataViewIsImage

    if len(self.GetProjectName()) == 0:
        return()
    buf = self.dataview.get_buffer()
    enc = buf.get_text(buf.get_start_iter(),buf.get_end_iter(),False)
    self.AddData2Db(DataViewNode,enc)

    format = buf.register_serialize_tagset()
    data = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

    sql = "UPDATE " + self.GetProjectName() + " SET tDataPath=%s  WHERE tNodeID=%s"
    val = (data, DataViewNode)

    self.cursor.execute(sql,val)
    self.mariadb_connection.commit()

和即时通讯使用它来创建表

sql = "CREATE TABLE %s (tParentNodeID TEXT,tNodeTxt TEXT,tNodeID TEXT,tDataPath LONGBLOB)" %pName
    self.cursor.execute(sql)
    self.mariadb_connection.commit()