【问题标题】:Store Gtk.Textbuffer in SQL database. Encoding troubles将 Gtk.Textbuffer 存储在 SQL 数据库中。编码问题
【发布时间】:2018-11-18 03:13:25
【问题描述】:

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

注释存储在 MySQL 数据库中并显示在 TextView widget 中。 我可以加载/存储/显示纯文本。但是我希望能够将图像添加到笔记页面,并将它们存储在数据库中。所以数据必须被序列化,我在弄清楚如何编码/解码序列化的过程中遇到了一些麻烦进出数据库的数据。我收到 unicode 起始字节错误。如果正在处理文件,我可以以二进制模式打开文件,但我将作为字符串存储在数据库中。我已经使用bytes() 和string.encode()[参见下面的示例代码] 以及其他一些方法尝试将 编码/解码 为 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()

这是存储文本视图缓冲区的函数:

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')

这是我遇到的错误。

Traceback(最近一次调用最后一次):文件“Boxer.py”,第 402 行,在 _TreeSelectionChanged self.SaveDataView() 文件“Boxer.py”,第 334 行,在 SaveDataView data = data2.decode(encoding='UTF-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb4 in position 174: invalid start byte Traceback(最近一次调用最后一次):文件“Boxer.py”,第 398 行,在 _DataViewLostFocus self.SaveDataView() 文件“Boxer.py”,第 334 行,在 SaveDataView data = data2.decode(encoding='UTF-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb4 in position 174: invalid start byte

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

【问题讨论】:

  • 这对我有用:c.execute("UPDATE products SET description = %s WHERE id = 1", (psycopg2.Binary(data),))。但那是使用 PostgreSQL 和 Psycopg2。您没有指定用于连接 MySQL 的软件。
  • 感谢您的回复。我正在使用 mysql.connector 连接到 mariadb(我使用 linux,但这没关系)

标签: python sql character-encoding gtk glade


【解决方案1】:

这是一个更完整的例子:

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 类型。

附:抱歉,我的回答中没有完整的 MySQL 示例。我会发表评论,但是 cmets 对于正确的格式是可悲的。

【讨论】:

  • 嘿,谢谢,我试试看。该错误发生在反序列化调用上,所以我什至没有考虑更改列类型。但也许是数据库存储它的方式导致了问题。无论如何都值得一试
  • 其实我也是这样,直到我改变了列类型。希望这也能解决您的问题。
【解决方案2】:

得到它的工作原理。感谢 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()

【讨论】:

  • 对于其他来到这里的人,请接受您自己的回答。
猜你喜欢
  • 2011-04-26
  • 2017-08-17
  • 1970-01-01
  • 2015-11-09
  • 1970-01-01
  • 2017-01-27
  • 2019-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多