前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >pkg文件--一种简单的游戏资源打包格式

pkg文件--一种简单的游戏资源打包格式

作者头像
用户7886150
修改于 2020-11-24 03:13:06
修改于 2020-11-24 03:13:06
2.2K0
举报
文章被收录于专栏:bit哲学院bit哲学院

参考链接: Python中的打包pack和拆包unpack参数

.pkg文件的格式 

[四字节] 固定的内容, 值不重要  [四字节] 文件数目(unsigned int)  [四字节] 文件名表 的偏移(unsigned int)  [四字节] 文件名表 的长度(字节数)(unsigned int)  ……  中间一堆 各个文件的内容, 文件内容使用zlib压缩过  ……  直到  文件名表:  [两字节] 文件名长度  [文件名长度那么多字节] 文件名  [四字节] 固定的内容,值不重要  [四字节] 文件原长度  [四字节] 文件偏移  [四字节] 文件压缩后的长度  [两字节] 又一个文件名的长度  … 

例程:  打包 PKGEncode.py  用法 python PKGEncode.py dirname pathname.pkg 

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

import zlib, glob, os, sys, struct

filelist = []

class FileVisitor:

    def __init__(self, startDir=os.curdir):

        self.startDir = startDir

    def run(self):

        for dirname, subdirnames, filenames in os.walk(self.startDir, True):

            for filename in filenames:

                self.visit_file(os.path.join(dirname, filename))

    def visit_file(self, pathname):

        filelist.append({'filename':pathname, 'size':0, 'zlib_size':0, 'offset':0, 'relative_filename': pathname.replace(os.path.normpath(self.startDir)+os.sep, '')})

        #print filelist[-1]['relative_filename']

if __name__ == "__main__":

    if len(sys.argv[1]) < 3:

        print 'few parameter'

    else:

        source_dirname = sys.argv[1]

        out_filename = sys.argv[2]

        FileVisitor(source_dirname).run()

        total = len(filelist)

        fp = file(out_filename + '~', 'wb')

        fp.write('\x64\x00\x00\x00')

        fp.write(struct.pack('I', len(filelist)))

        fp.write(struct.pack('I', 0))

        fp.write(struct.pack('I', 0))

        offset = 16

        for index in range(total):

            item = filelist[index]

            item['offset'] = offset

            infile = file(item['filename'], 'rb')

            text = infile.read()

            infile.close()

            item['size'] = len(text)

            text = zlib.compress(text)

            item['zlib_size'] = len(text)

            fp.write(text)

            offset += item['zlib_size']

            print u'已压缩文件 %d/%d' % (index+1, total)

        filename_table_offset = offset

        for index in range(total):

            item = filelist[index]

            fp.write(struct.pack('H', len(item['relative_filename'])))

            fp.write(item['relative_filename'])

            fp.write('\x01\x00\x00\x00')

            fp.write(struct.pack('I', item['offset']))

            fp.write(struct.pack('I', item['size']))

            fp.write(struct.pack('I', item['zlib_size']))

            offset += 2 + len(item['relative_filename']) + 16

            print u'已输出路径 %d/%d' % (index+1, total)

        filename_table_len = offset - filename_table_offset

        fp.close()

        fp = file(out_filename + '~', 'rb')

        ret = file(out_filename, 'wb')

        fp.read(16)

        ret.write('\x64\x00\x00\x00')

        ret.write(struct.pack('I', len(filelist)))

        ret.write(struct.pack('I', filename_table_offset))

        ret.write(struct.pack('I', filename_table_len))

        copy_bytes = 16

        total_bytes = offset

        while True:

            text = fp.read(2**20)

            ret.write(text)

            copy_bytes += len(text)

            print u'最后的拷贝 %d%%' % (copy_bytes*100.0/total_bytes)

            if not text:

                break

        fp.close()

        ret.close()

        os.remove(out_filename + '~') 

解包 PKGDecode.py  用法 python PKGDecode.py pathname.pkg dirname 

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

import sys, os, struct, zlib

if __name__ == "__main__":

    if len(sys.argv) < 3:

        print 'few argument'

    else:

        pkgfilename = sys.argv[1]

        outdirname = sys.argv[2]

        pkgfile = file(pkgfilename, 'rb')

        pkgfile.read(4)

        filenums, = struct.unpack('I', pkgfile.read(4))

        filename_table_offset, = struct.unpack('I', pkgfile.read(4))

        filename_table_len, = struct.unpack('I', pkgfile.read(4))

        pkgfile.seek(filename_table_offset)

        for index in range(filenums):

            name_len, = struct.unpack('H', pkgfile.read(2))

            name = pkgfile.read(name_len)

            pkgfile.read(4)

            offset, = struct.unpack('I', pkgfile.read(4))

            size, = struct.unpack('I', pkgfile.read(4))

            zlib_size, = struct.unpack('I', pkgfile.read(4))

            current_pos = pkgfile.tell()

            pkgfile.seek(offset)

            text = pkgfile.read(zlib_size)

            text = zlib.decompress(text)

            pkgfile.seek(current_pos)

            outfilename = os.path.join(outdirname, os.path.join(os.path.splitext(os.path.basename(pkgfilename))[0], name))

            print u'进度 [%d/%d]: ' %(index+1, filenums), os.path.join(os.path.splitext(os.path.basename(pkgfilename))[0], name)

            if not os.path.exists(os.path.dirname(outfilename)):

                os.makedirs(os.path.dirname(outfilename))

            file(outfilename, 'wb').write(text) 

感谢python各种库的方便  这两个程序也可以作为自己的压缩解压工具

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
RC4 with Python
""" RC4加密算法 16*16 S盒 加密单元:short """ def RC4(pkey,keylen,pin,dlen): N=65536 S = list(range(N)) j = 0 for i in range(N): j = (j + S[i] + pkey[i%keylen])%N temp = S[i] S[i] = S[j] S[j] = temp i = j = 0 pout= b'' for x in range(dlen): i = i+1 j = (j + S[i])%N temp = S[i] S[i] = S[j] S[j] = temp pout += struct.pack('H',pin[x]^S[(S[i]+S[j])%N]) return(pout)
py3study
2020/01/10
8410
[MYSQL] mysql怎样单表导入? && 从binlog提取指定表
上一篇文章介绍了 并发导入, 但还有一种需求是 只恢复特定的某张表. 比如这张表有坏块啊, 或者其它啥需求, 反正就是要恢复这张表, 但是又没单独备份这张表.
大大刺猬
2024/03/01
7880
[MYSQL] mysql怎样单表导入? && 从binlog提取指定表
PYTHON 自作类tar工具 实现 数据归档,压缩,加密功能
对目录打包(归档),我们一般使用tar之类的命令来做, 原生的tar命令是单线程的, 也不支持加密操作. 当然可以借助第三方工具来实现, 但都使用第三方工具了, 为何不自己写一个呢.
大大刺猬
2023/04/19
1.1K0
PYTHON 自作类tar工具 实现 数据归档,压缩,加密功能
Python之struct
  (3) 处理二进制数据,如果用struct来处理文件的话,需要用‘wb’/’rb’以二进制写,读的方式来处理文件
全栈程序员站长
2022/07/14
5000
Python 模版(三)
用于对特定的配置进行操作,当前模块的名称在python 3.x版本中变更为ConfigParser。
py3study
2020/01/14
5.2K0
配置文件管理维护到gitlab上(下)
二.脚本 服务端 ecs-file-master.py 要修改脚本,host为服务端ip,git的url为项目地址,要手动建好 #!/usr/bin/python3 #当同一个文件更新2次时,则提交一次到线上 #nohup /usr/bin/python3 -u /root/bin/ecs-file-master.py >> /var/log/ecs-file-master.log 2>&1 & from socket import * import sys, time, os, json, struct
陈不成i
2021/05/31
3500
[MYSQL] 主从连接协议(2)--GTID
之前有讲MYSQL连接协议, 也有讲过主从连接协议. 并附有相关python测试代码. 但对于主从连接的时候, GTID获取还是借用的现有的, 也就是没有做解析. 在我们解析了binlog之后. gtid信息就不在话下了. 格式就是PRE_GTID, 我这里就不再介绍了. 有兴趣的自己去看 https://www.modb.pro/db/1781217154309378048
大大刺猬
2024/05/08
1590
[MYSQL] 主从连接协议(2)--GTID
[MYSQL] REDUNDANT行格式的数据解析
mysql的行格式有4种,REDUNDANT,COMPACT,DYNAMIC和COMPRESSED. 最常用的就是DYNAMIC, 也是mysql默认的行格式(很早只有REDUNDANT). 该行格式虽然复杂一点, 但是支持的索引前缀可达3072字节.(REDUNDANT只支持到768字节).
大大刺猬
2024/12/06
2340
[MYSQL] REDUNDANT行格式的数据解析
[MYSQL] mysql.ibd 文件解析 (sdi page) (非debug模式下查看隐藏系统表)
在mysql 8.0版本,系统表的存储引擎由myisam改为了innodb, @@datadir/mysql目录下一堆的数据文件通通放到@@datadir/mysql.ibd文件中了. 但很多表在非debug模式下是无法查看里面的数据的. 这TM就很恼火. (刚学完innodb的磁盘结构, 我能受这气?). 所以我们现在来解析下mysql.ibd文件. (也顺便为 ibd2sql 2.0 做准备)
大大刺猬
2024/09/18
8800
[MYSQL] mysql.ibd 文件解析 (sdi page) (非debug模式下查看隐藏系统表)
面向对象之套接字(socket)和黏包
 一丶套接字(socket)   tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端   基于UDP协议的socket   server端: import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字 udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.s
py3study
2020/01/19
6030
面向对象之套接字(socket)和黏包
【十】python基础之文件处理
给要打开的文件对象指定一个名字,这样可在完成操作之后迅速关闭文件,防止一些无用的文件对象占用内存
菲宇
2019/06/13
7070
【十】python基础之文件处理
用struct模块实现python so
最近跳槽到西安一家机器人公司,我们的产品属于教育机器人的范畴,为了增强客户吸引力,引进了一个智能家居公司的产品API接口,让机器人来操作智能家居
py3study
2020/01/07
6240
python网络-TFTP客户端开发(25)
TFTP(Trivial File Transfer Protocol,简单文件传输协议)
Se7eN_HOU
2019/09/11
2.4K0
python网络-TFTP客户端开发(25)
python3中的struct模块使用
struct是python(包括版本2和3)中的内建模块,它用来在c语言中的结构体与python中的字符串之间进行转换,数据一般来自文件或者网络。
py3study
2020/01/10
2.2K0
大文件下载以及进度条展示和MD5校验
使用socket网络,上传一个视频,大小在3G左右 能够显示进度条,显示花费时间 下载使用TCP协议 server向client发送文件 新建文件server.py,代码如下: import os import json import socket import struct filepath = r'E:\BaiduYunDownload\[电影天堂www.dy2018.com]移动迷宫3:死亡解药BD国英双语中英双字.mp4' sk = socket.socket() sk.bind(('127.0
py3study
2018/08/02
7110
蓝队的反制(2)
 还有几天,某大型全国性交友活动就要开始了,特此为蓝队的朋友们献上一篇简单的反制文章。
鸿鹄实验室
2021/04/01
9040
蓝队的反制(2)
python bin文件处理
  rb  以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
py3study
2020/01/08
4.4K0
python bin文件处理
[MYSQL] MY-012095 表空间ID不对
有时候需要使用mysql的数据文件做恢复, 或者其它某些异常导致mysqld启动的时候报错如下:
大大刺猬
2024/09/13
4000
[MYSQL] MY-012095 表空间ID不对
Python UDP 协议网络编程《七》
温馨提示: 今日内容与前期推文Python UDP 协议网络编程《五》具有一定的关联性,是在该文章的基础上进行的再一次改造。如果Python UDP 协议网络编程《五》没有阅读的小伙伴,建议先阅读后,再来学习今天的内容,会有一个比较直观的对比。(点击蓝色字体的推文名称即可查看上一篇文章全部内容)。
Wu_Candy
2022/07/04
3150
Python UDP 协议网络编程《七》
Python UDP 协议网络编程《三》
TFTP 是一个传输文件的简单协议,它基于UDP协议而实现。 TFTP (Trivial File Transfer Protocol):简称文件传输协议。 TFTP 是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议,传输不复杂、开销不大的文件。端口号固定为69。
Wu_Candy
2022/07/04
4610
Python UDP 协议网络编程《三》
相关推荐
RC4 with Python
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档