记一个有趣的 Python ZipInfo 的副作用

0x00 前言

昨天修了一个有趣的 BUG,顺手分享出来。

本文目录

1
2
3
4
5
6
▼ 0x00 前言 : section
本文目录 : section
▼ 0x01 场景 1 - 空文件打包问题 : section
▼ 0x02 场景 2 - zipinfo 带来的一个副作用 : section
▼ 0x03 处理 BUG 的一种姿势 : section
▼ 0xEE 结论 : section

0x01 场景 1 - 空文件打包问题

原始场景是这样的,在打包文件夹的时候,一切正常,但如果打包空文件夹的时候,就出问题了。

精简了这一段代码,当打包空文件夹的时候,大致逻辑如下

1
2
3
4
5
import zipfile
zfile = zipfile.ZipFile("tmp.zip",'w')
# 递归打包所有子文件
zfile.close()

这段代码很明显是造了一个空 zip 文件。

这个和我要的效果还不太一样。我要的是这个 zip 文件包含空目录 tmp/ 好,调整了一下代码。

1
2
3
4
5
6
7
import zipfile
zfile = zipfile.ZipFile("tmp.zip",'w')
zif = zipfile.ZipInfo("tmp/")
zfile.writestr(zif,"")
# 递归打包所有子文件
zfile.close()

嗯,现在下载成功了。解压缩也正常。

0x02 场景 2 - zipinfo 带来的一个副作用

显然,如果上面的东西皆大欢喜的结束了,我就没必要写这篇文章了。

问题来了,当我递归打包子文件的时候,文件会莫名其妙多了一个文件夹出来。

比如我打包文件夹 tmp,tmp 的内容如下

1
2
3
4
5
$ tree tmp
tmp
├── test.md
1 file

打包完毕多出了一个 tmp 文件夹

1
2
3
4
5
6
$ tree tmp
tmp
├── test.md
└── tmp
1 directory, 1 file

这种多出一个 tmp 的文件夹就是按照我这种方式使用 zipinfo 副作用。

WTF,怀着老鹿蹒跚的内心,打开了《伤心太平洋》:

1
2
3
一波还未平息
一波又来侵袭
茫茫人海 狂风暴雨

用代码复现一波场景

1
2
3
# 先造一个测试文件夹
mkdir /tmp/test_folder/
touch /tmp/test_folder/test.md
1
2
3
4
5
6
7
8
import zipfile
file_path = "/tmp/test_folder/test.md"
rel_name = "test.md"
zfile = zipfile.ZipFile("tmp.zip",'w')
zif = zipfile.ZipInfo("tmp/")
zfile.writestr(zif,"")
zfile.write(file_path, rel_name)
zfile.close()

0x03 处理 BUG 的一种姿势

  1. 场景能否描述出来 - 描述不出来的就没法准确定位问题
  2. 能否复现 - 复现不出来的 BUG 最难调试
  3. 业务问题还是技术问题 - 业务问题可能要和别人打交道,技术问题可能要多翻翻文档之类的。
  4. 时间是否来得及 - 如果时间来的及,就想办法弄懂,填坑;时间来不及就想办法规避,绕坑。

前三点自然不用说了,直接第四点,时间上还算充裕,

  1. 我翻了半天 zipfile 模块,并没有理解这个 BUG 的出现原因。
  2. 好,退后一步是人生,用代码规避掉这个问题。
1
2
3
4
5
6
7
8
9
import zipfile
if 是空文件夹:
zfile = zipfile.ZipFile("tmp.zip",'w')
zif = zipfile.ZipInfo("tmp/")
else 不是空文件夹:
zfile.writestr(zif,"")
zfile.write(file_path, rel_name)
zfile.close()

0xEE 结论

其实处理大部分的 BUG 基本上就是这么个思路:

  • 往前一步是黄昏:打破沙锅问到底的去探究,填坑
  • 退后一步是人生:没那么多时间搞明白细枝末节,用代码规避掉这个神奇 BUG,先让业务可以跑通,绕坑。

最后,欢迎关注我的知乎专栏,咱们聊聊我所知道的 Python / NodeJS/ Mac / DevOps 全栈(干)工程师的一些有趣的技术