Слияние кода завершено, страница обновится автоматически
#coding:utf8
'''
File: mbg2csb.py
Author: 张宇飞
Description: 用来将CrazyStorm的弹幕文件转化成解析用的数据文件
Date: 2014-07-28
'''
import struct
############| 配置 |############
BODY_SELF = -99998 #自身
AUTO_SELF = -99999 #自机
ASSIGN_POS = -100000 #指定坐标
#几种内置对象类型
EMITTER = 0
LASER = 1
INTER_OBJ_NUM = 2 #被支持的内置对象个数
INTER_OBJ_LIMIT = 5 #内置对象的总个数
#几种条件定义
CON_BIG_THAN = 0x0
CON_EQUAL = 0x1
CON_LESS_THAN = 0x2
CON_SIGN_TRUE = 0x0
CON_AND = 0x1
CON_OR = 0x2
CON_TO = ':' #变化到
CON_ADD = '+' #增加
CON_SUB = '-' #减少
CON_ME_DRATIO = 'D' #正比
CON_ME_FIXED = 'F' #固定
CON_ME_SIN = 'S' #正弦
#目标字节序
TARGET_BYTE_ORDER = '<'
############| 用于组织文件格式的数据类 |############
def bool_str(s):
return 'True' == s
def nfind(s, c, n):
'''查找s中c的第n次出现位置'''
try:
b = 0
for k in xrange(0, n):
b = s.find(c,b)
if -1 == b:
return -1
b += 1
return b
except:
return -1
def emLaMaActionDivider(data, conmap, resmap):
''' 将一串数据分割成可以给发射器激光和遮罩使用的事件 '''
#事件组是用&分割的,;用来分割事件(NOTE:遮罩,发射器,激光的事件是一样的可以用一个通用方法处理)
if not data:
return []
ret = []
tmp = data.split("&")
tmp.pop()
trendmap = {"变化到":CON_TO, "增加":CON_ADD, "减少":CON_SUB}
methodmap = {"固定":CON_ME_FIXED, "正弦":CON_ME_SIN, "正比":CON_ME_DRATIO}
logicsign = (('>', CON_BIG_THAN), ('<', CON_LESS_THAN), ('=', CON_EQUAL))
for k in tmp:
s = nfind(k, '|', 3)
head = k[:s].split('|')
head.pop()
tail = k[s:].split(';')
tail.pop()
if not tail:
continue
a = {'interval':int(head[1]), 's':int(head[2]), 'ac':[]}
for tk in tail:
ac1 = tk.split(":")
newmap = {'cond':[]}
#判定条件的或且
two = ac1[0].split('或')
if len(two) > 1:
#或分割的
newmap['ncon']=CON_OR
else:
two = ac1[0].split('且')
if len(two) > 1:
#且分割的
newmap['ncon']=CON_AND
else:
newmap['ncon']=CON_SIGN_TRUE
#对每个条件取得量,逻辑运算符,值
for o in two:
for sign in logicsign:
one = o.split(sign[0])
if len(one) == 2:
newmap['cond'].append({'which':conmap[one[0]],'sign':sign[1], 'num':float(one[1])})
break
#result的特殊处理
three = ac1[1].split(",")
if len(three) == 1:
#应该交给对应的类处理
newmap['result'] = ac1[1]
else:
#对结果进行分解运算
newmap['result'] = {'method':methodmap[three[1]]}
frame = three[2].split("帧")
#变化需要的时间
newmap['result']['changetime'] = int(frame[0])
#变化次数(0表示永远)
if not frame[1]:
newmap['result']['ntimes'] = 0
else:
newmap['result']['ntimes'] = int(frame[1][1:len(frame[1])-1])
#结果描述
for sign in trendmap:
two = three[0].split(sign)
if len(two) == 2:
newmap['result']['which'] = resmap[two[0]]
newmap['result']['sign'] = trendmap[sign]
if '自机' == two[1]:
newmap['result']['num'] = AUTO_SELF
else:
newmap['result']['num'] = float(two[1])
break
a['ac'].append(newmap)
ret.append(a)
return ret
class CSObj(object):
'''内置元素, 接口类'''
UNUSEFUL_ID = -1
def __init__(self, tp, oridata):
super(CSObj, self).__init__()
self.t = tp
self.analyze(oridata.split(','))
def analyze(self, data):
pass
def data(self):
return None
def action2data(paction):
"""将paction转化成C结构二进制的字流"""
ret = ''
for k in paction:
#3I事件间隔,间隔增量,事件个数
ret += struct.pack("%c3I" % TARGET_BYTE_ORDER, k['interval'], k['s'], len(k['ac']))
for ack in k['ac']:
if len(ack['cond']) == 1:
#一个的时候需要加上一个永真
tAs = ack['cond'][0]['which'] | (0 << 8) | (ack['cond'][0]['sign'] << 16) | \
(CON_EQUAL << 18) | (ack['ncon'] << 20)
ret += struct.pack("%ci2f" % TARGET_BYTE_ORDER, tAs, ack['cond'][0]['num'], 0)
else:
tAs = ack['cond'][0]['which'] | (ack['cond'][1]['which'] << 8) | (ack['cond'][0]['sign'] << 16) | \
(ack['cond'][1]['sign'] << 18) | (ack['ncon'] << 20)
ret += struct.pack("%ci2f" % TARGET_BYTE_ORDER, tAs,ack['cond'][0]['num'],ack['cond'][1]['num'])
#bc?i2I
res = ack['result']
if res['which'] < 0:
#特别处理这个事件结果
ret += struct.pack("%cb2c?f2I" % TARGET_BYTE_ORDER, res['which'], CON_TO, CON_ME_FIXED,
False, 0, 0, 0)
else:
ret += struct.pack("%cb2c?f2I" % TARGET_BYTE_ORDER, res['which'], res['sign'], res['method'],
0 == res['ntimes'], res['num'], res['changetime'],
res['ntimes'])
return ret
class Emitter(CSObj):
"""发射器的类"""
# 发射器的事件编号
emconname = ("当前帧", "X坐标", "Y坐标", "半径", "半径方向",
"条数", "周期", "角度", "范围", "宽比",
"高比", "不透明度", "朝向")
# 变化的结果
emresname = ("X坐标", "Y坐标", "半径", "半径方向", "条数", "周期",
"角度", "范围", "速度", "速度方向", "加速度",
"加速度方向", "生命", "类型", "宽比", "高比",
"R", "G", "B", "不透明度", "朝向", "子弹速度",
"子弹速度方向", "子弹加速度", "子弹加速度方向",
"横比", "纵比", "雾化效果", "消除效果",
"高光效果", "拖影效果", "出屏即消", "无敌状态")
#特殊的结果
superresname = {"恢复到初始状态":-2, "额外发射":-3}
emconmap = {}
for k in emconname:
emconmap[k] = emconname.index(k)
emresmap = {}
for k in emresname:
emresmap[k] = emresname.index(k)
# 发射器子弹的事件编号
buconname = ("当前帧", "X坐标", "Y坐标")
buresname = ("生命", "类型", "宽比", "高比", "R", "G", "B",
"不透明度", "朝向", "子弹速度", "子弹速度方向",
"子弹加速度", "子弹加速度方向", "横比", "纵比",
"雾化效果", "消除效果", "高光效果", "拖影效果",
"出屏即消", "无敌状态")
buconmap = {}
for k in buconname:
buconmap[k] = buconname.index(k)
buresmap = {}
for k in buresname:
buresmap[k] = buresname.index(k)
def __init__(self, oridata):
self.action = [] #事件
self.bullet = {'action':[]} #子弹事件
super(Emitter, self).__init__(EMITTER, oridata)
def analyze(self, data):
#data[0] , data[1]发射器ID, 层ID(忽略)
#data[2],绑定了吗, data[3],绑定的ID (忽略) ,data[4] 相对方向不使用, data[5]抛弃使用
self.pos = (float(data[6]), float(data[7])) #位置坐标
self.frame = (int(data[8]), int(data[8]) + int(data[9])) #播放的起始结束帧存两个uint32
self.emitpos = (float(data[10]), float(data[11]), float(data[53]), float(data[54])) #发射坐标存两个float, 和其随机量
#发射器半径和旋转角度,及其它们的随机量float
self.emitedge = (float(data[12]), float(data[13]), float(data[55]), float(data[56]))
self.nmuzzle = (int(data[15]), int(data[57])) #炮口数量uint16
self.freq = (int(data[16]), int(data[58])) # 发射周期及其随机量uint32
self.angle = (float(data[17]), float(data[59])) #发射起始方向旋转角度以及角度的随机量float
self.emitrange = (int(data[19]), int(data[60])) #射击范围及其随机量,存int16
self.v = (float(data[20]), float(data[21]), float(data[61]), float(data[62])) #速度和速度方向及随机量
self.va = (float(data[23]), float(data[24]), float(data[63]), float(data[64])) #加速度和加速度方向及随机量
#73深度绑定(忽略)
####### 以下是子弹信息 #######
#data[38] 是子弹的初始速度方向,不使用
#是否受到遮罩,反弹板和力场的控制(忽略)
#self.bullet['factor'] = (bool_str(data[70]), bool_str(data[71]), bool_str(data[72]))
self.bullet['life'] = int(data[26]) #子弹生命 uint32
self.bullet['ID'] = int(data[27]) #子弹类型 int32
self.bullet['WHscale'] = (float(data[28]), float(data[29])) #宽高比(y方向和x方向的缩放倍率)
self.bullet['color'] = (int(data[30]), int(data[31]),int(data[32])) #RGB的颜色叠加值,存3个uint8_t
self.bullet['alpha'] = int(data[33]) * 255 / 100 #透明度 uint8_t
self.bullet['sangle'] = (int(data[34]), int(data[65])) #朝向及随机量 int16_t
#print "sangle is %d"%self.bullet['sangle']
self.bullet['v'] = (float(data[37]), float(data[66])) #子弹的初速度及随机量 float
#子弹的加速度和加速度方向及其随机量
self.bullet['va'] = (float(data[40]), float(data[41]), float(data[68]), float(data[69]))
self.bullet['xyvrate'] = (float(data[43]), float(data[44])) #x,y方向的加速度的倍率
#七个个bool(雾化,消弹, 发射高亮,拖影,出屏消亡,无敌,朝向是否使用发射器发出的起始速度方向)
self.bullet['effect'] = (bool_str(data[45]), bool_str(data[46]),bool_str(data[47]), \
bool_str(data[48]), bool_str(data[49]), bool_str(data[50]), bool_str(data[36]))
#发射器事件处理
self.action = emLaMaActionDivider(data[51], Emitter.emconmap, Emitter.emresmap)
for k in self.action:
#k是事件组
for ack in k['ac']:
#ack是每一个事件
if type(ack['result']) == str:
ack['result'] = {'which':Emitter.superresname[ack['result']]}
#子弹事件处理
self.bullet['action'] = emLaMaActionDivider(data[52], Emitter.buconmap, Emitter.buresmap)
def data(self):
'''返回格式化的数据 '''
#2I起始结束帧, 4f发射半径和旋转角度, 2I发射周期 , 8f速度和加速度,
#2f发射起始方向, 2h射击范围,2H炮口数量
ret = struct.pack("%c2I4f2I8f2f2h2H" % TARGET_BYTE_ORDER, self.frame[0], self.frame[1],
self.emitedge[0], self.emitedge[1], self.emitedge[2],self.emitedge[3],
self.freq[0], self.freq[1], self.v[0], self.v[1], self.v[2], self.v[3],
self.va[0], self.va[1], self.va[2], self.va[3], self.angle[0], self.angle[1],
self.emitrange[0], self.emitrange[1], self.nmuzzle[0], self.nmuzzle[1])
#发射坐标2i,发射器事件组个数I
ret += struct.pack("%c4fI" % TARGET_BYTE_ORDER, self.emitpos[0], self.emitpos[1],
self.emitpos[2], self.emitpos[3], len(self.action))
#发射器事件
ret += action2data(self.action)
#iI子弹类型和生命, 2f速度和速度随机量,4f加速度和加速度随机量, 2f X:Y方向的缩放
bu = self.bullet
ret += struct.pack("%ciI2f4f2f" % TARGET_BYTE_ORDER, bu['ID'], bu['life'], bu['v'][0], bu['v'][1],
bu['va'][0],bu['va'][1],bu['va'][2],bu['va'][3],
bu['WHscale'][1],bu['WHscale'][0])
#计算特效
effect = 0
tmp = 0
for k in bu['effect']:
if k:
effect = effect | (1<<tmp)
tmp += 1
#子弹4B颜色, 2f加速度缩放, i特效, I子弹事件组个数
ret += struct.pack("%c4B2fiI" % TARGET_BYTE_ORDER, bu['color'][0],bu['color'][1],bu['color'][2],
bu['alpha'], bu['xyvrate'][0],bu['xyvrate'][1], effect, len(bu['action']))
#print bu['action']
#子弹事件
ret += action2data(bu['action'])
return ret
class Laser(CSObj):
"""发射器的类"""
# 发射器的事件编号
emconname = ("当前帧", "半径", "半径方向",
"条数", "周期", "角度", "范围", "宽比",
"长度", "不透明度")
# 变化的结果
emresname = ( "半径", "半径方向", "条数", "周期",
"角度", "范围", "速度", "速度方向", "加速度",
"加速度方向", "生命", "类型", "宽比", "长度",
"不透明度", "子弹速度", "子弹速度方向", "子弹加速度", "子弹加速度方向",
"横比", "纵比", "高光效果", "出屏即消", "无敌状态")
#特殊的结果
superresname = {"恢复到初始状态":-2, "额外发射":-3}
emconmap = {}
for k in emconname:
emconmap[k] = emconname.index(k)
emresmap = {}
for k in emresname:
emresmap[k] = emresname.index(k)
# 发射器子弹的事件编号
buconname = ("当前帧", "X坐标", "Y坐标")
buresname = ("生命", "类型", "宽比", "高比", "R", "G", "B",
"不透明度", "朝向", "子弹速度", "子弹速度方向",
"子弹加速度", "子弹加速度方向", "横比", "纵比",
"雾化效果", "消除效果", "高光效果", "拖影效果",
"出屏即消", "无敌状态")
buconmap = {}
for k in buconname:
buconmap[k] = buconname.index(k)
buresmap = {}
for k in buresname:
buresmap[k] = buresname.index(k)
def __init__(self, oridata):
self.action = [] #事件
self.bullet = {'action':[]} #子弹事件
super(Laser, self).__init__(LASER, oridata)
def analyze(self, data):
#data[0] , data[1]发射器ID, 层ID(忽略)
#data[2],绑定了吗, data[3],绑定的ID (忽略) ,data[4] 相对方向不使用, data[5]抛弃使用
self.pos = (float(data[6]), float(data[7])) #位置坐标
self.frame = (int(data[8]), int(data[8]) + int(data[9])) #播放的起始结束帧存两个uint32
self.emitedge = (float(data[10]), float(data[11]), float(data[44]), float(data[45]))
self.nmuzzle = (int(data[13]), int(data[46])) #炮口数量uint16
self.freq = (int(data[14]), int(data[47])) # 发射周期及其随机量uint32
self.angle = (float(data[15]), float(data[48])) #发射起始方向旋转角度以及角度的随机量float
self.emitrange = (int(data[17]), int(data[49]))#射击范围及其随机量,存int16
self.v = (float(data[18]), float(data[19]), float(data[50]), float(data[51])) #速度和速度方向及随机量
self.va = (float(data[21]), float(data[22]), float(data[52]), float(data[53])) #加速度和加速度方向及随机量
#73深度绑定(忽略)
####### 以下是子弹信息 #######
#data[38] 是子弹的初始速度方向,不使用
#是否受到遮罩,反弹板和力场的控制(忽略)
#self.bullet['factor'] = (bool_str(data[70]), bool_str(data[71]), bool_str(data[72]))
self.bullet['life'] = int(data[24]) #子弹生命 uint32
self.bullet['ID'] = int(data[25]) #子弹类型 int32
self.bullet['WHscale'] = (float(data[26]), float(data[27])) #宽高比(y方向和x方向的缩放倍率)
self.bullet['alpha'] = int(data[28]) * 255 / 100 #透明度 uint8_t
self.bullet['startX'] = (bool_str(data[29])) #开启射线激光
self.bullet['v'] = (float(data[30]), float(data[54]))#子弹的初速度及随机量 float
#子弹的加速度和加速度方向及其随机量
self.bullet['va'] = (float(data[33]), float(data[34]), float(data[56]), float(data[57]))
self.bullet['xyvrate'] = (float(data[36]), float(data[37])) #x,y鏂瑰悜鐨勫姞閫熷害鐨勫€嶇巼
self.bullet['effect'] = (bool_str(data[38]), bool_str(data[39]),bool_str(data[40]))
#发射器事件处理
self.action = emLaMaActionDivider(data[42], Laser.emconmap, Laser.emresmap)
#子弹事件处理
self.bullet['action'] = emLaMaActionDivider(data[43], Laser.buconmap, Laser.buresmap)
def data(self):
'''返回格式化的数据 '''
#2I起始结束帧, 4f发射半径和旋转角度, 2I发射周期 , 8f速度和加速度,
#2f发射起始方向, 2h射击范围,2H炮口数量
ret = struct.pack("%c2I4f2I8f2f2h2HI" % TARGET_BYTE_ORDER, self.frame[0], self.frame[1],
self.emitedge[0], self.emitedge[1], self.emitedge[2],self.emitedge[3],
self.freq[0], self.freq[1], self.v[0], self.v[1], self.v[2], self.v[3],
self.va[0], self.va[1], self.va[2], self.va[3], self.angle[0], self.angle[1],
self.emitrange[0], self.emitrange[1], self.nmuzzle[0], self.nmuzzle[1],len(self.action))
#发射器事件
ret += action2data(self.action)
#iI子弹类型和生命, 2f速度和速度随机量,4f加速度和加速度随机量, 2f X:Y方向的缩放
bu = self.bullet
ret += struct.pack("%ciI2f4f2f" % TARGET_BYTE_ORDER, bu['ID'], bu['life'], bu['v'][0], bu['v'][1],
bu['va'][0],bu['va'][1],bu['va'][2],bu['va'][3],
bu['WHscale'][1],bu['WHscale'][0])
#计算特效
effect = 0
tmp = 0
for k in bu['effect']:
if k:
effect = effect | (1<<tmp)
tmp += 1
ret += struct.pack("%c4B2f2iI" % TARGET_BYTE_ORDER,255,255,255,
bu['alpha'], bu['xyvrate'][0],bu['xyvrate'][1], effect, bu['startX'],len(bu['action']))
ret += action2data(bu['action'])
return ret
class Layer(object):
"""格式化数据的类"""
def __init__(self):
super(Layer, self).__init__()
self.objarr = [] #元素对象
for k in range(0, INTER_OBJ_NUM):
self.objarr.append([])
def addObj(self, obj):
#判定元素类型
self.objarr[obj.t].append(obj.data())
def objNum(self):
ret = 0
for k in self.objarr:
ret += len(k)
return ret
def formatData(self):
"""返回格式化的数据"""
#起始结束帧,每种元素的数量
ret = ''
for k in self.objarr:
ret += struct.pack("%cI" % TARGET_BYTE_ORDER, len(k))
#发射器和激光的数据长度
for k in self.objarr:
for p in k:
#加的20是下面的名字长度16 + 一个整形类型的4
ret += struct.pack("%cI" % TARGET_BYTE_ORDER, len(p) + 20)
#元素的类型,元素的名称, 元素的值
objname = ('em', 'la')
t = 0
for k in self.objarr:
tmp = 0
for p in k:
#NOTE:元素的名称由'类型名#编号'组成, 不能超过16个字符长度
name = '%s#%d' % (objname[t], tmp)
if len(name) > 15:
print '错误: 需要缩减文件名长度'
exit()
while len(name) < 16:
name += chr(0)
ret += struct.pack("%ci16s" % TARGET_BYTE_ORDER, t, name)
ret += p
tmp += 1
t += 1
return ret
class CSB_Data(object):
"""格式化数据的类"""
def __init__(self):
super(CSB_Data, self).__init__()
self.version = 0x01 #数据版本
self.layer = [] #层对象
self.totalframe = 0 #总帧数
def addLayer(self, player):
if player and (player.objNum() > 0):
self.layer.append(player)
def formatData(self):
"""返回格式化的数据"""
#文件头: 版本号,总数据长度,层数
ret = ''
for k in self.layer:
ret += k.formatData()
return struct.pack("%c3I" % TARGET_BYTE_ORDER, self.version, len(self.layer), self.totalframe) + ret
############| 分析函数 |############
def readLayer(ldata, csbdata, CSObjArr):
'''读取一层的数据ldata,分析它,然后写入csbdata
ldata 是一个OBJ_NUM长度的数组,每个数组里面又是一个数组。
每个元素是一个obj
'''
# 创建一个层
pl = Layer()
#依次解析各种结构
idx = 0
for k in ldata:
for lk in k:
pl.addObj(CSObjArr[idx](lk))
idx += 1
#添加到解析层内
csbdata.addLayer(pl)
def showhelp(name):
l = (60 - len(name)) / 2
#TODO: 添加j表示json文件
print '#' * l + '|', name, '|' + '#' * l
print '用法:'
print ' python %s [-b b|l] [-R] <弹幕编辑器出来的mbg文件列表|递归查找mbg文件的路径>' % name
print ' -b 指定使用何种字节序进行文件的数据排布。'
print ' b大端字节序,l小端字节序。默认使用小端。'
print ' -R 指定递归查找mbg文件的路径。此参数就忽略文件列表。'
print '要求:'
print ' 弹幕文件版本需是CrazyStorm 1.01或其以上'
print '#' * 64
############| 入口函数 |############
if __name__ == '__main__':
from sys import argv
#获取字节序
try:
bidx = argv.index('-b')
try:
o = argv[bidx + 1]
if 'b' == o:
TARGET_BYTE_ORDER = '>'
elif 'l' == o:
#默认就是小端字节序
pass
else:
showhelp(argv[0])
exit()
except IndexError:
showhelp(argv[0])
exit()
#剔除两个字节序控制位
bidx = 3
except ValueError:
bidx = 1
try:
ridx = argv.index('-R')
ridx += 1
except ValueError:
ridx = -1
if ((ridx < 0) and len(argv[bidx:]) < 1) or (len(argv[ridx:]) < 1):
showhelp(argv[0])
exit()
if 'j' == TARGET_BYTE_ORDER:
print '>>>>>>>>>>>>> Use format Json print <<<<<<<<<<<<<'
else:
print '>>>>>>>>>>>>> 22222222222%s <<<<<<<<<<<<<' % ('大' if '>' == TARGET_BYTE_ORDER else '小')
#取得文件列表
srcflist = []
if ridx < 0:
srcflist = argv[bidx:]
else:
import os
for parent, dirnames, fnames in os.walk(argv[ridx]):
for f in fnames:
if 'mbg' == f[-3:]:
srcflist.append(os.path.join(parent, f))
for srcfile in srcflist:
try:
fp = open(srcfile, "rb")
#输出文件的名字
outfile = ''
p = srcfile.rfind('.')
if p < 0:
outfile = srcfile
else:
outfile = srcfile[:p]
outfile += '.csb'
#检测文件头版本
fline = fp.readline()
FILE_HEAD = "Crazy Storm Data 1.01"
if FILE_HEAD != fline[:len(FILE_HEAD)]:
print '%s 文件不是版本为1.01的Crazy Storm Data文件' % srcfile
continue
csbdata = CSB_Data()
#读取中心坐标(忽略掉)
fline = fp.readline()
if fline[0] != 'C':
for k in range(int(fline.split()[0]) + 1):
fp.readline()
#读取总帧数(忽略掉)
fline = fp.readline()
csbdata.totalframe = int(fline.split(':')[1])
#检测是否是可读的层(一共4层,不为empyt就可读)
CSObjArr = (Emitter, Laser)
for k in xrange(0, 4):
fline = fp.readline().split(':')[1]
if 'empty' == fline[:len('empty')]:
continue
fdata = fline.split(',')
#依次是:图层名, 起始帧,结束帧,发射器数目,激光数目,遮罩数目,反弹板数目,力场数目
objarr = []
for key in xrange(0, INTER_OBJ_NUM):
objarr.append([])
for key in xrange(3, 3 + INTER_OBJ_NUM):
idx = key - 3
for j in xrange(0, int(fdata[key])):
objarr[idx].append(fp.readline())
#抛弃掉遮罩等力场数据
for key in xrange(3 + INTER_OBJ_NUM, 3 + INTER_OBJ_LIMIT):
for j in xrange(0, int(fdata[key])):
fp.readline()
readLayer(objarr, csbdata, CSObjArr)
fp.close()
except IOError:
print '读取文件 %s 时出现IO错误' % srcfile
continue
try:
#开始写入文件
fp = open(outfile, "wb")
fp.write(csbdata.formatData())
fp.close()
print '%s ----> %s' % (srcfile, outfile)
except IOError:
print '写入文件时出现IO错误'
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )