同样还是学习@斌叔的程序媛课程的笔记~
第四课
本次运用本课程的Socket和sqlite3 改一下这个程序,通过socket将日记保存至数据库中:
整体流程如下图:
Screen Shot 2018-04-11 at 4.46.56 PM.png.png
client.py 是客户端
server.py 是服务端
database.py 是数据库模块
diary.py 是中级课程中的日记本
首先从数据库开始,把它们抽象成一个类,作为一个模块,方便使用
showAllData 用于展示数据,可以在调试的时候使用,方便我们看到结果是否正确
getDataDict 用于获取数据,并将数据拼成字典形式返还给客户端
sqlite.py
import sqlite3
class DB(object):
"""docstring for DB"""
def __init__(self):
super(DB, self).__init__()
self.connect = sqlite3.connect("test.db")
self.cursor = self.connect.cursor()
def searchTable(self,tableName):
flag = False
self.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table' ")
for item in self.cursor.fetchall():
if item[0] == tableName:
flag = True
break
return flag
def initTable(self,tableName):
if self.searchTable(tableName) == False:
sql = "CREATE TABLE " + tableName + "(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT , content TEXT)"
self.cursor.execute(sql)
print(u"创建表成功")
else:
print(u"该表已存在")
def insertData(self, tableName, data):
sql = "INSERT INTO " + tableName + "(title, content) VALUES (?, ?)"
self.cursor.execute(sql,data)
self.connect.commit()
return "保存成功"
def deletaData(self, tableName, id):
sql = "DELETE FROM " + tableName + " WHERE id = " + str(id)
self.cursor.execute(sql)
self.connect.commit()
return "删除成功"
def updateData(self, tableName,id,data):
sql = "UPDATE " + tableName + " SET title = '" + data[0] + "', content = '" + data[1] + "' Where id = " + str(id)
self.cursor.execute(sql)
self.connect.commit()
return "修改成功"
def searchData(self, tableName, id):
sql = "SELECT * FROM " + tableName + " WHERE id = " + str(id)
self.cursor.execute(sql)
tup = self.cursor.fetchone()
dict = {'title': tup[1], 'content': tup[2]}
return str(dict)
def showAllData(self, tableName):
sql = "SELECT * FROM " + tableName
for row in self.cursor.execute(sql):
print(row)
def getDataDict(self, tableName):
dict = {}
i = 0
sql = "SELECT * FROM " + tableName
for row in self.cursor.execute(sql):
item = {"id":row[0],"title":row[1]}
dict[str(i)] = item
i += 1
return str(dict)
def close(self):
self.cursor.close()
self.connect.close()
main.py (使用之前封装好的类)
import socket
import sqlite #导入模块 自己命名的
import re
name = "diary"
sqlite.DB().initTable(name)
sqlite.DB().insertData(name, ("title100","content100"))
sqlite.DB().deletaData(name, 2)
sqlite.DB().updateData(name, 10, ("title300","content300"))
sqlite.DB().searchData(name, 1)
sqlite.DB().showAllData(name)
sqlite.DB().close()
接下类写一个比较完整的日志demo,可以用之前中级班应用Tkinter代码做修改
改后:
Screen Shot 2018-04-16 at 5.05.25 PM.png Screen Shot 2018-04-16 at 5.05.35 PM.png
代码:(这是我写的,但是仍旧运行不了!求大神赐教!)
diary.py
from tkinter import * #导入 Tkinter 库
import os
import socket
def write():
textVar.set("") #清空 entry
text.delete("0.0","end") #清空 text
label.config(text = "写日记模式")
listBox.pack_forget() #隐藏 listBox
entry.pack() #显示 entry
text.pack #显示 pack
def save():
title = textVar.get() + ".txt" # 获取标题
content = text.get("0.0", "end") # 获取内容
if title != ".txt":
# fileObj = open(title, "wb") # 打开一个文件
# fileObj.write(content.encode(encoding = "utf-8")) # 写入内容
# fileObj.close() # 关闭打开的文件
# label.config(text = "已保存")
s = socket.socket()
s.connect(('127.0.0.1',1234))
print(s.recv(1024))
#将标题,内容写成字典
dict = {'title':title,'content':str(content)}
s.send(str(dict).encode(encoding = "utf-8"))
data = s.recv(1024)
s.close()
label.config(text = data)
else:
label.config(text = "请输入标题")
def read():
listBox.delete(0,END) # 清空 listBox
# dir = os.getcwd() # 获取当前目录
# list = os.listdir(dir) # 获取目录内所有文件
showText = "看日记模式"
s = socket.socket() # 创建 socket 对象
s.connect(('127.0.0.1',1234)) # 链接服务器
print(s.recv(1024)) # 打印信息
s.send("read".encode(encoding = "utf-8")) # 发送一个 read 字符串
data = s.recv(2048) # 收到数据 (字符串格式)
dict = eval(data) # 间数据转为字典格式
s.close() # 关闭链接
if len(list) == 0: # 如果当前没有日记
showText += "(日记本是空的)" # 设置提示
label.config(text = showText)
for item in dict.values(): # 因为数据库中日记标题可能有相同的,加一个id 来区分一下
string = str(item['id']) + ':' + item['title']
listBox.insert(0,string)
listBox.bind('<Double-Button-1>',showDiary) # 绑定双击事件
entry.pack_forget() # 隐藏 entry
text.pack_forget() # 隐藏 text
listBox.pack() # 显示 listBox
def showDiary(event):
title = listBox.get(listBox.curselection()) # 获取点击的日记名
showTitle = title[:-4] # 截取至倒数第4个字符(即不显示.txt)
textVar.set(showTitle) # 设置日记标题
id = title.split(':')[0] # 截取日记的id
data = 'show' + id # 拼接字符串
s = socket.socket()
s.connect(('127.0.0.1',1234))
print(s.recv(1024))
s.send(data.encode(encoding = "utf-8"))
data = s.recv(1024) # 服务器返回数据
content = eval(data)['content'] # 转为字典后取出 content 的值
s.close()
# fileObj = open(title, "r+") # 打开对应标题的文件
# content = fileObj.read(); # 获取文件内容
text.delete("0.0", "end") # 清空 text
text.insert("end", content) # 把内容显示在 text 上
# fileObj.close() # 关闭打开的文件
listBox.pack_forget() # 隐藏 listBox
entry.pack() # 显示 entry
text.pack() # 显示 text
#创建日记文件夹
def initDiary():
dir = os.getcwd() # 获取当前.py目录
list = os.listdir(dir) # 获取当前目录中的所有文件
haveDiary = False # 设置一个变量,是否存在diary文件夹,默认为 False
for item in list: # 遍历
if item == "diary": # 判断是否存在 diary 文件夹
haveDiary = True # 如果有,设置 diary 为Ture
if haveDiary == False: # 如果 haveDiary 为 False
os.mkdir("diary") # 创建 diary 文件夹
os.chdir("./diary") # 改变 .py 工作目录到 diary 内
initDiary()
root = Tk() #创建窗口
root.geometry('500x400') #窗口的frame
root.title("窗口的名字")
saveBtn = Button(root, text = "Save",command=save)
saveBtn.pack(side=LEFT,anchor='sw') #pack 是一种布局方式 ancher是一种对齐方式
quitBtn = Button(root,text = "Exit")
quitBtn.pack(side=RIGHT,anchor="se")
#command=write 表示点击这个按钮时候,会执行 write 方法,然后我们来写一下 write 方法
writeBtn = Button(root, text="写日记", command=write)
writeBtn.pack(side=BOTTOM, anchor='s')
readBtn = Button(root,text = "read",command=read)
readBtn.pack(side=BOTTOM)
label = Label(root)
label.pack()
label.config(text = "This is a demo")
textVar = StringVar()
entry = Entry(root, textvariable = textVar)
entry.pack()
listBox = Listbox(root, height = 300)
text = Text(root)
text.pack()
root.mainloop() #开始事件循环
这几节课我们做了很多插入、更改等操作,先清空一下我们的表
或者直接将 test.db 数据库删除也行,因为都是胡乱写入的测试数据
database.py
#!/usr/bin/env python
#coding:utf-8
import sqlite3
class DB:
def __init__(self):
self.connect = sqlite3.connect("test.db")
self.cursor = self.connect.cursor()
def searchTable(self, tableName):
flag = False
self.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
for item in self.cursor.fetchall():
if item[0] == tableName:
flag = True
break
return flag
def initTable(self, tableName):
if self.searchTable(tableName) == False:
sql = "CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)"
self.cursor.execute(sql)
print(u"创建表成功")
else:
print(u"该表已存在")
def insertData(self, tableName, data):
sql = "INSERT INTO " + tableName + "(title, content) VALUES (?, ?)"
self.cursor.execute(sql, data)
self.connect.commit()
return ("保存成功")
def deleteData(self, tableName, id):
sql = "DELETE FROM " + tableName + " WHERE id = " + str(id)
self.cursor.execute(sql)
self.connect.commit()
return ("删除成功")
def updateData(self, tableName, id, data):
sql = "UPDATE " + tableName + " SET title = '" + data[0] + "', content = '" + data[1] + "' WHERE id = " + str(id)
self.cursor.execute(sql)
self.connect.commit()
return ("修改成功")
def searchData(self, tableName, id):
sql = "SELECT * FROM " + tableName + " WHERE id = " + str(id)
self.cursor.execute(sql)
tup = self.cursor.fetchone()
dict = {'title': tup[1], 'content': tup[2]}
return str(dict)
def showAllData(self, tableName):
sql = "SELECT * FROM " + tableName
for row in self.cursor.execute(sql):
print(row)
def getDataDict(self, tableName):
dict = {}
i = 0
sql = "SELECT * FROM " + tableName
for row in self.cursor.execute(sql):
item = {'id':row[0],'title':row[1]}
dict[str(i)] = item
i += 1
return str(dict)
def close(self):
self.cursor.close()
self.connect.close()
def dropTable(self, tableName):
sql = 'DROP TABLE IF EXISTS ' + tableName
self.cursor.execute(sql)
self.connect.commit()
return ("表已删除或不存在")
def clearTable(self, tableName):
# 清空表数据
sql = "DELETE FROM " + tableName
# 设置自增 id 为 0
reset = "UPDATE sqlite_sequence SET seq = 0 WHERE name = '" + tableName + "'"
# 注意 '" + tableName + "'" 这不是 3个' + 5个',而是两个双引号中间一个单引号
# 为了加以区分这样来写,如果不拼接的话就是下面这样
# "UPDATE sqlite_sequence SET seq = 0 WHERE name = 'diary'"
self.cursor.execute(sql)
self.cursor.execute(reset)
self.connect.commit()
return ("表已清空")
# 以下是改写为函数前的代码,不明白的可以看看理解一下
# # 创建一个名为 diary 的表,并设置一个 id 为自增主键,title、content 为 text 类型
# cursor.execute("CREATE TABLE diary (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)")
# # 向表中插入数据,因为是自增主键,id 可以写成 NULL,表中 id 值会是 1、2、3…… 递增
# cursor.execute("INSERT INTO diary VALUES (NULL, 'title1', 'content1')")
# # 或者也可以这样写
# cursor.execute("INSERT INTO diary(title, content) VALUES ('title2', 'content2')")
# # 查询表中所有数据,并输出
# for row in cursor.execute("SELECT * FROM diary"):
# print row
# print u"***** 增 ***** \n"
# # 删除表中 id 为 1 的数据
# cursor.execute("DELETE FROM diary WHERE id = 1")
# # 再输出所以数据,验证是否删除成功
# for row in cursor.execute("SELECT * FROM diary"):
# print row
# print u"***** 删 ***** \n"
# # 修改 id 为 2 的数据
# cursor.execute("UPDATE diary SET title = 'title0', content = 'content0' WHERE id = 2")
# # 再输出所以数据,验证是否修改成功
# for row in cursor.execute("SELECT * FROM diary"):
# print row
# print u"***** 改 ***** \n"
# items = [("title0", "content0"),("title1", "content1"),("title2", "content2")]
# # executemany 一次向标准插入多条数据
# cursor.executemany("INSERT INTO diary(title, content) VALUES (?, ?)", items)
# print u"插入多条数据后的表:"
# for row in cursor.execute("SELECT * FROM diary"):
# print row
# print u"查 id 为 5 的数据:"
# cursor.execute("SELECT * FROM diary WHERE id = 5")
# print cursor.fetchall()
# print u"查 title 为 title0 的数据:"
# cursor.execute("SELECT * FROM diary WHERE title = 'title0'")
# print cursor.fetchall()
# cursor.close()
# connect.close()
server.py
#!/usr/bin/env python
#coding:utf-8
import socket
import database
import re
s = socket.socket()
s.bind(('127.0.0.1', 1234))
s.listen(5)
while True:
c, addr = s.accept()
print(u'连接地址为:', addr)
c.send('成功链接至服务器...'.encode())
# 客服端发来的数据
# 1、'read'
# 表示点击看日记,则去读取数据库中所有日记的标题和 id
# 2、'show5' (5 为 id)
# 表示双击日记名,则去数据库中查找 id 为 5 的日记并返回
# 3、'{"title": "cxy", "content": "adcd"}'
# 这是一个由包含日记信息字典转成的字符串,则插入数据
data = c.recv(1024) # 接收客户端的数据(3种情况)
if data:
tableName = 'diary' # 表名
database.DB().initTable(tableName) # 创建表
database.DB().showAllData(tableName) # 显示所有数据,方面我们看结果
if data == 'read':
print('看日记')
c.send(database.DB().getDataDict(tableName)) # 将返回数据发给客服端
elif data[0:4] == 'show': # 判断字符串前4个字符是否为 show
id = re.sub(r'\D', '', data) # 用正则删除非数字字符
print('查日记:', id)
c.send(database.DB().searchData(tableName, id).encode()) # 根据 id 查表中数据,发送结果
else:
dict = eval(data) # 将字符串转为字典
print(dict) # 打印,方便我们看结果
tup = (dict['title'], dict['content']) # 写成元组格式,方便数据插入
print(tup)
c.send(database.DB().insertData(tableName, tup).encode()) # 插入数据
database.DB().close()
c.close()
# 使用 database 模块 DB 类中方法的试例
# name = 'diary'
# database.DB().initTable(name)
# database.DB().insertData(name, ('title100','content100'))
# database.DB().deleteData(name, 2)
# database.DB().updateData(name, 10, ('title300','content300'))
# database.DB().searchData(name, 10)
# database.DB().showAllData(name)
# database.DB().close()
# 清空表、删除表的试例子
# database.DB().initTable('diary')
# print database.DB().insertData('diary', ('title100','content100'))
# print database.DB().insertData('diary', ('title100','content100'))
# print u'表中数据为:'
# database.DB().showAllData('diary')
# print '\n'
# print database.DB().clearTable('diary')
# print u'表中数据为:'
# database.DB().showAllData('diary')
# print '\n'
# print database.DB().insertData('diary', ('title100','content100'))
# print database.DB().insertData('diary', ('title100','content100'))
# print u'清空后再插入两条数据,id 又从 1 开始计数'
# database.DB().showAllData('diary')
# print '\n'
# print database.DB().dropTable('diary')
# database.DB().showAllData('diary')
网友评论