Python通过protbuf 处理txt配置。序列化和反序列化

本文介绍了一个用于解析特定格式配置文件的工具,并能自动生成ProtoBuf定义文件及对应的序列化字节码,支持从配置文件中读取数据并转换为ProtoBuf消息格式,便于在网络传输和数据持久化中使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# -*- coding: utf-8 -*-#

# -------------------------------------------------------------------------------
# Name:         Tools
# Description:  
# Author:       zhangchunhui
# Date:         2019/1/27
# -------------------------------------------------------------------------------
import collections
import os
import sys
import xml.etree.ElementTree as ET

from pip._vendor import chardet

ConfigPath = "./Config/Server"


class DataParser:
   def __init__(self, fullFileName, fileName):
      """
      读取文件内容
      :param fullFileName:
      :param fileName:
      """
      # print(fullFileName)
      print(fileName)
      # f = open(fullFileName, "rb")
      # data = f.read()
      # print(chardet.detect(data))
      # f.close()
      self.fileName = fileName.split('.')[0]
      file = open(fullFileName, 'r', encoding='GB18030')
      self.strCounts = file.read()
      self.list = self.strCounts.split('\n')
      file.close()

   def dealTitel(self):
      """
      处理标题
      :return:
      """
      self.titleDic = collections.OrderedDict()
      self.effectrow = []
      if (len(self.list) > 4):
         titleList = self.list[0].split('\t')
         titleTypeList = self.list[1].split('\t')
         if titleList.__len__() != titleTypeList.__len__():
            print("标题有问题 请检查:" + self.fileName)
            return
         for i in range(0, len(titleList)):
            titleStrName = titleList[i].strip()
            titleStrType = titleTypeList[i].strip()
            if (len(titleStrName) > 0 and len(titleStrType) > 0):
               self.titleDic[titleStrName] = titleStrType
               self.effectrow.append(i)

      else:
         print("配置文件出问题 请检查%s", self.fileName)

   def printTest(self):
      """
      输出查看
      :return:
      """
      for i in range(0, len(self.list)):
         str1 = self.list[i]
         print(str1)

   def writeProto3(self):
      """
      写出protoBuff3文件
      :return:
      """
      dom = ET.parse('ProtoTemplate.xml')
      importListStr = dom.getiterator("import")
      cousntStr = importListStr[0].text
      self.protoFileName = self.fileName + ".proto";
      cousntStr += "message " + self.fileName
      cousntStr += "\n{\n"
      i = 1
      for titleStr1 in self.titleDic.keys():
         cousntStr += " " + getProtoType(self.titleDic[titleStr1]) + " " + titleStr1 + " = " + str(i) + ";\n"
         i += 1
      cousntStr += "}\n"

      cousntStr += "message " + self.fileName + "_ARRAY\n"
      cousntStr += "{\n  repeated " + self.fileName + " items = 1;";
      cousntStr += "\n}\n"
      file = open("./protofile/" + self.protoFileName, 'w+', encoding='utf-8')
      file.write(cousntStr)
      file.close()

   def writeUTF8File(self):
      """
      写入文件信息
      :return:
      """
      file = open("./Out/" + self.fileName + ".txt", 'w+', encoding='utf-8')
      file.write(self.strCounts)
      file.close()

   def WritePythonCode(self):
      """
      生成proto文件
      :return:
      """
      command = "protoc --python_out=./ " + "./protofile/" + self.protoFileName
      os.system(command)

   def DealDataByte(self):
      data = ""
      try:
         self._module_name = self.fileName + "_pb2"
         sys.path.append(os.getcwd() + "./protofile")
         exec('from ' + self._module_name + ' import *')
         self._module = sys.modules[self._module_name]
      except Exception as e:
         print("Load error" + e + self.fileName)
         return
      item_array = getattr(self._module, self.fileName + '_ARRAY')()
      for i in range(3, len(self.list)):
         # print(self.list[i])
         # 如果 id 是 空 直接跳过改行
         str1 = self.list[i].strip()
         if (len(str1) > 0):
            str1List = str1.split('\t')
            if (len(str1List) > 0 and len(str1List[0]) > 0 and str1List[0].find("#") < 0):
               item = item_array.items.add()
               self._ParseLine(item, str1List)
      data = item_array.SerializeToString()
      self.writeDataByte(data)

   def _ParseLine(self, item, lineList):
      """
      初始化一行数据
      :param item:
      :return:
      """
      i = 0
      for key in self.titleDic.keys():
         # 如果 id 是 空 直接跳过改行
         fild_value = getProtoValue(getProtoType(self.titleDic[key]), lineList[self.effectrow[i]])
         item.__setattr__(key, fild_value)
         i += 1

   def writeDataByte(self, data):
      """
      生成byte文件
      :param data:
      :return:
      """
      file_name = self.fileName + ".bin"  # self._proto_name.lower() + ".bin"
      file = open("./bytedata/" + file_name, 'wb+')
      file.write(data)
      file.close()


ProtoTypeDic = {"int": "int32", "string": "string", "float": "float"}


def getProtoType(typeStr):
   """
   获取类型转换
   :param typeStr:
   :return:
   """
   typeStr = typeStr.lower()
   return ProtoTypeDic.get(typeStr, "nothing")


def getProtoValue(typeStr, valueStr):
   """
   获取值信息
   :param typeStr:
   :param valueStr:
   :return:
   """
   try:
      if typeStr == "int32" or typeStr == "int64" \
            or typeStr == "uint32" or typeStr == "uint64" \
            or typeStr == "sint32" or typeStr == "sint64" \
            or typeStr == "fixed32" or typeStr == "fixed64" \
            or typeStr == "sfixed32" or typeStr == "sfixed64":
         if len(str(typeStr).strip()) <= 0:
            return 0
         else:
            return int(valueStr)
      elif typeStr == "double" or typeStr == "float":
         if len(str(typeStr).strip()) <= 0:
            return float(0)
         else:
            return float(valueStr)
      elif typeStr == "string":
         return valueStr
      elif typeStr == "bytes":
         valueStr = valueStr.encode('utf-8')
         return valueStr
      else:
         return None
   except BaseException as e:
      print("parse cell(%u, %u) error, please check it, maybe type is wrong." % (typeStr, valueStr))
      raise


def gci(filepath):
   """
   读取所有的txt 文件
   :param filepath:
   :return:
   """
   files = os.listdir(filepath)
   for fi in files:
      fi_d = os.path.join(filepath, fi)
      if os.path.isdir(fi_d):
         gci(fi_d)
      else:
         txtInfo = DataParser(fi_d, fi)
         # txtInfo.writeUTF8File()
         # txtInfo.printTest()
         txtInfo.dealTitel()
         txtInfo.writeProto3()
         txtInfo.WritePythonCode()
         txtInfo.DealDataByte()


if __name__ == '__main__':
   gci(ConfigPath)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值