刚接触py,挺多不熟悉的API,第一次使用py写工具(边做边学,感觉很充实):
===========源码在最下面============
该工具作用:指将.xls/.xlsx导成指定格式的:.xml
程序工作流程:
1)、读取收集所有需要导入.xls/xlsx文件名集合;
2)、逐个文件导成.xml;
3)、zip打包所有.xml到cfg.zip压缩包;
还有一些CMD批处理脚本(一些cmd.bat就不写了,该.bat的作用:执行该py工具,并将cfg.zip包替换并复制到游戏资源目录)
现在已使用py2exe,再将该工具,打包一下,其它程序员,或是策划,都可以使用了;帅呆了!
(py2exe与安装的py版本有关,这个要注意)
该工具,是xls2xml;准备开始写个:dbtable2xml (database table 2 xml)
dbtable2xml的工具也写好了;
对于第一版的xls2xml来说,算是,结构上,工程学管理上的一个很不一样的管理方式;
在任何公司,任何项目都可以使用;(不过这个版,目前是针对后台是使用MySQL为数据库的,如果MS SQL的话,或是其它的话,就只能再写另一个数据库版本的)
因为dbtable2xml的管理导配置是,插件式的:加载用户简单的py脚本方式来处理导表,用户脚本只要输出以下简单的脚本即可,基本上,只要动action方法即可;
第二版dbtable2xml的用户脚本Deme.py的代码:
#encoding="utf-8"
import MySQLdb
import types
import sys
import os
sys.path.append("..")
from base.OutputBase import OutputBaseCls
# need to handle content
def action():
global outputBase
outputBase = OutputBaseCls(getXmlName())
sql = "select tb.id, tb.name from tableName tb limit 2" # 基本上,只要动这个sql参数即可,除非你还要连不动的数据来导配置,那就要动其它的参数了
outputBase.action(sql,
host = 'dbhost',
user = 'username',
passwd = 'password',
db = 'dbname',
port = 8001,
charset = 'gbk'
)
# special output xml file name
def getXmlName():
# return "AwardCfg"
fn = __file__
fn = os.path.basename(fn)
fn = fn[0:fn.rindex(".")]
return fn
# xml file content str
def getXmlStr():
return outputBase.getXmlStr()
# dispose res
def dispose():
outputBase.dispose()
而且,还基本上是,只能action中的sql参数即可;非常灵活;
就三大部分组成
1)、Main.py:去管理输出文件,错误日志,用户脚本加载,打包配置;
2)、OutputBase.py:管理sql连接,与查询结果转字符,回收;
3)、Demo.py(在Main.py的相对目录下的script目录下的.py都为用户脚本,py2exe后,就在.exe相对目录下的script放脚本即可):
设置sql连接参数,设置sql执行脚本,调用OutputBase.py的转化xml内容;设置.xml文件名,默认为:模块名.xml的方式输出;
如:
script目录下,放个:ItemConfig.py,那么最后在cfg.zip下,就会有一个ItemConfig.xml的配置;
第二版的打包版工具下载:dbtable2xml
修改:script/Demo.py,script/Demo.py中的,mysql连接配置,与sql脚本,运行Main.exe,在dbtable2xml目录下的output就是输出内容
其中:cfg.zip就是我们要的配置文件
第三版:将中,第二版中,script/Demo.py,script/Demo2.py这种方式的管理,改成:单个outputcfg.xml的方式来管理
该xml的格式内容大概如此
但是,使用该xml有一些不太理像的就是:sql中,如果带有html、xml的标签类的关键字符的话,那配置将失效;
所以,这个第三版,将考虑使用:.xml, .ini, .inf, 等;
或是纯:.txt也行;
但是,最后说明一下,使用.py来当做扩展用户脚本的最大好处:就是,一但用户脚本写错了哪些文本(代码),运行时,将有错误日志输出:调用堆栈。
调用堆栈对维护是非常方便的;
第三版的打包版工具下载:dbtable2xmlv2
最终,第三版是使用了:.ini来配置,用户就不用去编辑对他们来说难懂的.py脚本了;
只要动.ini即可:
.ini文件内容如:
一个.ini对应,一个数据库连接对象的操作
[db_cfg]
host=数据库地址(host或是ip)
user=登录帐号
passwd=登录密码
db=要连接的数据库
port=8001(端口号)
charset=gbk(字符集编码)
[script_cfg]
Demo="select tb.id, tb.type, tb.key, tb.name, tb.award_list from tableName tb limit 2"
Demo2="select tb.id, tb.name from tableName tb limit 2"
如果说,要从:192.168.1.101取数据,又要从:192.168.1.102取数据;
那么最好在outputcfg文件夹下添加该两个文件即可:
"192.168.1.101.ini"
"192.168.1.102.ini"
这样就可以分别从两个不同的数据库连接中导配置;
script_cfg中的
左值=右值
左值:就是配置名
右值就是要筛选得来的脚本数据
上面两个Demo、Demo2最终就会导出:
Cfg.rar压缩文件内的:Demo.xml,Demo2.xml两个文件
如果还需要其它配置,则往下添加即可;
第一版xls2xmls工具源代码:
#encoding="utf-8"
'''
output xls files to game's client config files(.xml)
author : Jave.Lin(afeng)
date : 2013-08-06
'''
import xlrd
import os
import getopt
import sys
import zipfile
import types
# cur path
CUR_PATH = os.getcwd() # os.path.abspath('.') # also can do that
CUR_XLS_PATH = CUR_PATH + "\\client_xls"
OUT_PUT_PATH = CUR_PATH + "\\output_client_xml"
PRINT_FLAG = True
PACKAGE_OUT_PUT_FULL_NAME = CUR_PATH + "\\cfg.zip"
def myPrint(*args):
if(PRINT_FLAG):
print args
def package():
zipfiles = zipfile.ZipFile(PACKAGE_OUT_PUT_FULL_NAME, "w", compression = zipfile.ZIP_DEFLATED)
packagedFileNames = getPathAllFullNameArr(OUT_PUT_PATH)
for f in packagedFileNames:
zipfiles.write(f, os.path.basename(f))
zipfiles.close()
# myPrint("Zip finished!")
'''
def unpackage():
zipfiles = zipfile.ZipFile(PACKAGE_OUT_PUT_FULL_NAME, "r")
unpackagePath = CUR_PATH + "\\unzip_output"
path = os.path.dirname(unpackagePath)
if(os.path.exists(path) == False):
os.makedirs(path)
zipfiles.extractall(unpackagePath)
zipfiles.close()
# myPrint("unZip finished!")
'''
def getPathAllFullNameArr(path):
result = []
for root, dirs, files in os.walk(path):
for file in files:
result.append(os.path.join(root, file))
return result;
# myPrint "CUR_PATH = " + CUR_PATH
# myPrint "CUR_XLS_PATH = " + CUR_XLS_PATH
# list all dirs, files of path
def getDirsFiles(path):
dirsFilesInfo = os.listdir(path)
# myPrint(dirsFilesInfo)
return dirsFilesInfo
# for info in dirsFilesInfo:
# myPrint info
# filter all dirs, to files
def filterFiles(dirsFilesInfo):
result = []
for info in dirsFilesInfo:
# not dir, but files
# os.path.isdir()
fullName = CUR_XLS_PATH + "\\" + info
if(os.path.isfile(fullName)):
# push it
# myPrint(info + " is a file")
result.append(fullName)
else:
# myPrint(info + " not is a file")
pass
return result
def getXLSData(fullName):
data = xlrd.open_workbook(fullName)
return data;
def getSheetByName(xlsData, name):
tables = xlsData.sheets()
for t in tables:
if(t.name == name):
return t
def outputTxtFile(fullName, content):
path = os.path.dirname(fullName)
if(os.path.exists(path) == False):
os.makedirs(path)
codedContent = content.encode("utf8")
f = file(fullName, "w")
f.write(codedContent)
f.close()
def getColsNameArr(xlsData, sheet):
result = []
for colIdx in range(sheet.ncols):
result.append(sheet.cell(0, colIdx).value)
return result
def makeXML(xlsData, sheetFlag, outputFileName):
sheet = None
if(type(sheetFlag) is types.StringType):
sheet = getSheetByName(xlsData, sheetFlag)
else:
sheet = xlsData.sheets()[0]
colsArr = getColsNameArr(xlsData, sheet)
pureFileName = outputFileName[0:outputFileName.rindex('.')]
xmlStr = createXMLStr(sheet, pureFileName, colsArr)
outputFullName = OUT_PUT_PATH + "\\" + pureFileName + ".xml"
# myPrint("outputFullName = " + outputFullName)
outputTxtFile(outputFullName, xmlStr)
def createXMLStr(sheet, nodeName, colsArr):
root = "\n"
root += "\t\n" % nodeName
rowIdx = 1
colIdx = 0
'''
nrows = sheet.nrows
ncols = sheet.ncols
'''
while(rowIdx < sheet.nrows):
root += "\t\t\n"
rowIdx += 1
root += "\t\n" % nodeName
root += ""
return root
def main():
'''
# myPrint(sys.argv)
kvArgs, args = getopt.getopt(sys.argv[1:], "c:", "all")
# myPrint(kvArgs, args)
for kvObj in kvArgs:
# myPrint(kvObj) # ('-c', 'test')
if("-c" in kvObj):
k = kvObj[0]
v = kvObj[1]
print k + " = " + v
'''
# no src files, nothing to do...
if(os.path.exists(CUR_XLS_PATH) == False):
os.makedirs(CUR_XLS_PATH)
dfs = getDirsFiles(CUR_XLS_PATH)
# myPrint dfs
ffs = filterFiles(dfs)
# no src files, nothing to do...
if(len(ffs) == 0):
return
# myPrint ffs
# bat to output
for f in ffs:
xlsData = getXLSData(f)
pureFileName = os.path.basename(f)
makeXML(xlsData, "Sheet1", pureFileName)
package()
# unpackage()
# myPrint(__name__)
if(__name__ == "__main__"):
myPrint("start OutputXML script...")
main()
myPrint("end OutputXML script...")
源码dbtable2xmlv2下载