SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2021年已经接近有21个年头,SQLite也迎来了一个版本 SQLite 3已经发布。
以下是一个已经封装好的数据库类:
import sqlite3
import random
import time
import traceback
__all__ = ["Sql"]
def dict_str(d):
return ",".join([" ".join([k,v]) for k,v in d.items()])
# 连接数据库
class Sql:
def __init__(self,db,autoCommit = False):
self.conn = sqlite3.connect(db)
self.cur = self.conn.cursor()
self.conn.execute("BEGIN")
self.autoCommit = autoCommit
def createTable(self,name:str,headers:dict,debug = False): # 创建名为name的表,包含headers数据列,如果debug启用则当表存在时不会报错
self.cur.execute(f"CREATE TABLE {'if not exists ' if debug else ''}{name}({dict_str(headers)});")
if self.autoCommit:self.commit()
def delTable(self,table:str): # 删除名为table的表
self.cur.execute(f"DROP TABLE {table}")
if self.autoCommit:self.commit()
def columnCount(self,table): # 查询table表中的列数
self.cur.execute(f"SELECT COUNT(*) FROM {table}")
if self.autoCommit:self.commit()
return self.cur.fetchone()[0]
def insertValue(self,table:str,data:tuple): # 插入单行数据
self.cur.execute(f"INSERT INTO {table} VALUES ({('?,' * len(data))[:-1]});",data)
if self.autoCommit:self.commit()
def insertValues(self,table:str,data:list): # [(1,2,3),(4,5,6),...],插入多行数据
self.cur.executemany(f"INSERT INTO {table} VALUES ({('?,' * len(data[0]))[:-1]});",data)
if self.autoCommit:self.commit()
def updateValue(self,table:str,upd_header:str,upd_value:str,header:str,value:str): # 设置table表中upd_header列值为upd_value的行中header列的数据为value
self.cur.execute(f"UPDATE {table} set {header} = '{value}' WHERE {upd_header} = '{upd_value}'")
if self.autoCommit:self.commit()
def delValue(self,table:str,header:str,value:str): # 删除table表中header列值为value的整行数据
self.cur.execute(f"DELETE FROM {table} WHERE {header} = '{value}'")
if self.autoCommit:self.commit()
def delAll(self,table:str): # 删除某表中所有数据
self.cur.execute(f"DELETE FROM {table}")
if self.autoCommit:self.commit()
def getTableList(self): # 读取所有表列表
return [i[1] for i in self.getAll("sqlite_master")]
def getAll(self,table): # 读取整个表
self.cur.execute(f"SELECT * FROM {table}")
return self.cur.fetchall()
def getColumn(self,table,header): # 读取某列
self.cur.execute(f"SELECT {header} FROM {table}")
return self.cur.fetchall()
def getRow(self,table,row): # 查询一行
self.cur.execute(f"SELECT * FROM {table} LIMIT {row},1;")
return self.cur.fetchall()[0]
def getRows(self,table,row0,row1): # 查询多行(包括row1),返回生成器
return map(lambda x:getRow(table,x),range(row0,row1 + 1))
def sectionGetAll(self,table,block_size = 1000): # 分块读取整个表
offset = 0
while True:
# 查询数据
query = f"SELECT * FROM {table} LIMIT {offset}, {block_size}"
self.cur.execute(query)
data = self.cur.fetchall()
# 如果没有更多数据,跳出循环
if not data:
break
yield data
# 更新偏移量
offset += block_size
def copyDbTableToNowDb(self,dbpath,dbTable,nowTable):
self.cur.execute(f"ATTACH DATABASE '{dbpath}' AS copyTmpDb")
self.cur.execute(f"CREATE TABLE copyTmpDb.{dbTable} AS SELECT * FROM {nowTable}")
self.cur.execute(f"DETACH DATABASE copyTmpDb")
if self.autoCommit:self.commit()
def rollback(self): # 回滚更改
self.conn.rollback()
def commit(self): # 提交更改
self.conn.commit()
def close(self,commit = True): # 关闭数据库
self.conn.commit()
self.cur.close()
self.conn.close()
可以将其放到自己的项目文件夹里直接进行调用,更加方便。
Configure是已经封装好的配置类:
import json
import os
import sys
from PyQt5.QtWidgets import QMessageBox,QWidget
__all__ = ["MessageBox","Configure"]
def infoget(text):
print(text)
class MessageBox: # 可以改成你的报错弹窗,如使用easygui、tkinter等
class ButtonType:
Yes = QMessageBox.Yes
No = QMessageBox.No
Cancel = QMessageBox.Cancel
def _result(self,result):
if QMessageBox.Yes == result:
return self.ButtonType.Yes
elif QMessageBox.No == result:
return self.ButtonType.No
elif QMessageBox.Cancel == result:
return self.ButtonType.Cancel
else:
return None
parent = QWidget()
def info(self,title = "信息",text = "",buttons = ButtonType.Yes,defaultButton = ButtonType.Yes):
infoget(title.join(["MessageBox-info",":"]),text,type = "Info")
return self._result(QMessageBox.information(self.parent,title,text,buttons = buttons,defaultButton = defaultButton))
def warn(self,title = "警告",text = "",buttons = ButtonType.Yes,defaultButton = ButtonType.Yes):
infoget(title.join(["MessageBox-warn",":"]),text,type = "Warn")
return self._result(QMessageBox.warning(self.parent,title,text,buttons = buttons,defaultButton = defaultButton))
def err(self,title = "错误",text = "",buttons = ButtonType.Yes,defaultButton = ButtonType.Yes):
infoget(title.join(["MessageBox-error",":"]),text,type = "Error")
return self._result(QMessageBox.critical(self.parent,title,text,buttons = buttons,defaultButton = defaultButton))
def question(self,title = "提问",text = "",buttons = ButtonType.Yes | ButtonType.No,defaultButton = ButtonType.Yes):
infoget(title.join(["MessageBox-question",":"]),text,type = "Info")
return self._result(QMessageBox.question(self.parent,title,text,buttons = buttons,defaultButton = defaultButton))
MessageBox = MessageBox()
class Configure:
normalConfig = {}
def __init__(self,file = "Config.json",create = True):
self._state = 0
self._file = file
self._readConfigFile(create)
def __str__(self):
return "Configure({})".format(",".join([f"{k}={v}" for k,v in self._cfgdic.copy().items()])).replace("\n","\\n")
def _clearKey(self):
if hasattr(self,"_keyList"):
list(map(lambda x:(delattr(self,x),self._keyList.remove(x)),self._keyList))
def _dealConfigToDict(self,content): # str转dict(读取的配置)
try:
return json.loads(content)
except json.JSONDecodeError as err:
MessageBox.err(text = str(err))
return
except Exception as err:
MessageBox.err("未知错误",str(err))
return
def _dealConfigToStr(self,cfgdic): # dict转str(写入的配置)
try:
return json.dumps(cfgdic,ensure_ascii = False)
except Exception as err:
MessageBox.err("未知错误",f"加载配置字典到json字符串时发生错误:\n详细信息: {str(err)}")
return False
def _readConfigFile(self,create):
self._clearKey()
is_file_can = True
is_file_exists = True
if not isinstance(self._file,str):
MessageBox.err("软件错误","传入参数file数据类型错误")
is_file_can = False
elif not os.path.exists(self._file):
if not create:
MessageBox.err(text = f"配置文件\"{self._file}\"不存在")
else:
is_file_exists = False
is_file_can = False
elif not os.path.isfile(self._file):
MessageBox.err("文件错误",f"配置文件\"{self._file}\"不是一个有效的文件")
is_file_can = False
if is_file_can or create:
try:
self._file = os.path.abspath(self._file)
except Exception as err:
MessageBox.err(text = "获取配置文件绝对路径失败\n详细信息: {err}")
return
if is_file_exists:
try:
with open(self._file,"r",encoding = "utf-8") as f:
content = f.read()
except PermissionError as err:
MessageBox.err("读取文件失败",f"没有权限读取配置文件\"{self._file}\"\n详细信息: {str(err)}")
return
except Exception as err:
MessageBox.err("未知错误",str(err))
return
self._cfgdic = self._dealConfigToDict(content)
if not self._cfgdic:
return
self._loadCfgdic()
else:
self._cfgdic = self.normalConfig.copy()
self._loadCfgdic()
self.SaveConfigToFile()
self._state = 1
def _loadCfgdic(self):
self._keyList = []
try:
for k,v in self._cfgdic.copy().items():
if not isinstance(k,str):
self._clearKey()
MessageBox.err("配置文件错误",f"键\"{k}\"不是一个有效的键")
return
elif k in self._keyList:
self._clearKey()
MessageBox.err("配置文件错误",f"键\"{k}\"有重复项")
return
elif k.startswith("_"):
self._clearKey()
MessageBox.err("配置文件错误",f"键\"{k}\"不能以下划线开头")
return
elif k in ("GetConfigState",
"GetKeyList",
"GetConfigFilePath",
"SaveConfigToFile"):
self._clearKey()
MessageBox.err("配置文件错误",f"键\"{k}\"与类函数名重名")
return
else:
self._keyList.append(k)
setattr(self,k,v)
except Exception as err:
self._clearKey()
MessageBox.err("未知错误",str(err))
return
def GetConfigState(self):
return self._state
def GetKeyList(self):
return self._keyList
def GetConfigFilePath(self):
return self._file
def SaveConfigToFile(self,file = None):
if file == None:
file = self._file
if not isinstance(file,str):
MessageBox.err("软件错误","file数据类型错误")
return False
elif (not os.path.isfile(file)) and os.path.exists(file):
MessageBox.err("文件错误",f"配置文件\"{file}\"不是一个有效的文件")
return False
else:
try:
file = os.path.abspath(file)
except Exception as err:
MessageBox.err(text = "获取配置文件绝对路径失败\n详细信息: {err}")
return False
try:
content = {k:getattr(self,k) for k in self._keyList.copy()}
except Exception as err:
MessageBox.err("未知错误",f"加载配置字典时发生错误:\n详细信息: {str(err)}")
return False
content = self._dealConfigToStr(content)
try:
with open(file,"w",encoding = "utf-8") as f:
f.write(content)
except PermissionError as err:
MessageBox.err("写入文件失败",f"没有权限写入配置文件\"{file}\"\n详细信息: {str(err)}")
return False
except Exception as err:
MessageBox.err("未知错误",str(err))
return False
return True
修改Configure中的_dealConfigToDict和_dealConfigToStr函数可以更改读取配置文件的方式,这个例子读取的是json格式的配置文件 。
制作不易,感谢大家的关注与支持!