在GAE中使用zip压缩文件

标签:Google App Engine, Python

最近在做游戏王网页游戏时遇到个问题,目前卡片有3000多张,每张卡片需要一张大图,一张攻击和一张防守表示的小图,也就是需要9000多个静态文件。
虽然这些图总大小不超过100MB,但是GAE最多只允许1000个静态文件和1000个程序文件,所以是没法全部上传的。

于是考虑了几种方案,均不太理想:
  1. 存放到数据库。这样每次读取卡片信息都要获取大量数据,会导致性能下降。而如果单独用一个模型,则仍然会因为数据库访问而造成约0.1秒的延时。
  2. 存放到memcache。缺点很明显,数据不保证是永久存在,必须和其他方案搭配,只能算是backup。
  3. 存放到Picasa之类的相册。每个相册的文件数量有限制(500张),且路径是随机的,获取比较麻烦。虽然可以用API,但搜索后再分析会浪费大量时间。
没办法,只好想到了压缩。
由于Python内置了zipfile和tarfile这2个模块,因此处理压缩文件是很容易的。所以只要将所有文件都打包在一起,需要时再读取,就不会超过文件数量的限制了。
当然,由于单个文件不允许超过10MB,所以还是有必要分成几个压缩包的。

顺带一提:由于JPEG图像是已经压缩过的,再次压缩没有意义,且会导致解压速度变慢,所以我用的是存档方式的zip压缩,普通的文件则推荐使用压缩率高的bzip压缩。

下面就给个实现代码:
import wsgiref.handlers
from google.appengine.ext import webapp
from zipfile import ZipFile

class MainHandler(webapp.RequestHandler):
  def get(self):
    img = ZipFile('a.zip').read('a.jpg')  # 要解压的文件名是a.zip,这个zip文件里有个a.jpg文件。
    self.response.headers['Content-Type'] = 'image/jpeg'
    self.response.out.write(img)

def main():
  application = webapp.WSGIApplication([('/', MainHandler)])
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()
没错一行代码就实现了解压和读取,然后再设置文件头并输出图像内容即可,实在是简单得不行了…
要注意的是文件路径,我是与handler放在一个文件夹的。特别注意千万不要弄成static文件,不然获取文件会非常麻烦。

当然,为了减少开销,最好设置Expires和Cache-Control头,并用memcache进行缓存。
此外,图像变形可以用图像API来做,所以只需要传一张大图即可。

最后注意一点,GAE上的文件是不允许通过API修改和删除的,所以ZipFile不能用write和writestr方法。

0条评论 你不来一发么↓

    想说点什么呢?