python - Python 解释器如何检测它是使用 ZIP 存档而不是源文件调用的?

标签 python zip software-distribution

我刚刚发现 (A) ZIP 文件可以直接作为 Python 的 script 参数传递(通常会传递 .py 文件)二进制文件,(B) ZIP 文件可以有任何后缀,甚至是 .py 来被识别为 ZIP 文件(至少在 Mac OS X 上从命令行,在 Windows 上从命令行和从GUI,它似乎可以工作)。实现这一点的整个故事记录在this issue中。 .

这对于不需要安装程序的 Python 应用程序的分发来说似乎非常有吸引力,并且它具有与 .jar 存档相同的使用特征(无需安装,可以通过电子邮件发送,无需进一步存档)我们的用户已经习惯了。将 ZIP 存档命名为 .py(或 .pyw)即可实现此行为,除了安装 Python 之外,无需在客户端计算机上进行任何配置。

我的问题是我只能找到我的发现的 (A) 部分的文档,但找不到 (B) 部分的文档。所以我的第一个问题是 Python 如何检测作为 script 参数传递的文件是 ZIP 存档而不是 Python 源文件?是否涉及任何可能随机中断的启发式方法,例如当 ZIP 存档包含一些特殊内容(例如看起来像 Python 代码的未压缩文件)时?

第二个问题是,当应用程序携带大量非代码数据文件(数十 MB)时,除了对这些文件的访问不透明之外,这种方法是否有任何缺点。我正在考虑如果 ZIP 文件很大和/或包含大量文件,ZIP 文件检测会花费更长的时间。

更新

遗憾的是,迄今为止的所有答案(Joachim Sauer、Keith Randall 和 Curious)都是错误的。 Zip 规范并不强制 ZIP 文件必须以特定 header 开头。 Zip 文件可以在其前面添加任何数据,并且仍然是有效的 Zip 文件(这就是自解压 Zip 文件的工作原理,文件以 Windows EXE header 开头,而不是任何 Zip 特定的内容)。 Curious 的答案中链接的页面对此进行了解释。

我猜测 Python 解释器会查找 Zip 中央目录,如果有,则该文件将用作 Zip 文件而不是 Python 源文件。有人想将此包含在他/她的答案中以便我可以接受吗?

最佳答案

我也想知道并发现:

您是正确的,允许添加前置数据,并且在 docs 中明确提到了这一点。 :

Python has been able to execute zip files which contain a __main__.py file since version 2.6. In order to be executed by Python, an application archive simply has to be a standard zip file containing a __main__.py file [...]

The zip file format allows arbitrary data to be prepended to a zip file.

您对 Python 寻找 ZIP 中央目录的猜测也是正确的。这发生在 zipimport.py ,它会在文件末尾附近查找 STRING_END_ARCHIVE = b'PK\x05\x06'

因此,存档的内容(例如未压缩的 Python 代码文件)不会影响 zip 文件的检测。

演示:

$ echo 'print("hello")' > script.py
$ python script.py
hello
$ echo 'print("hi")' > __main__.py
$ zip app.zip __main__.py
  adding: __main__.py (stored 0%)
$ dd if=app.zip >> script.py
0+1 records in
0+1 records out
184 bytes transferred in 0.000066 secs (2786108 bytes/sec)
$ zip -A script.py
Zip entry offsets appear off by 15 bytes - correcting...
$ head -n 1 script.py 
print("hello")
$ unzip -l script.py 
Archive:  script.py
  Length      Date    Time    Name
---------  ---------- -----   ----
       12  08-04-2022 23:02   __main__.py
---------                     -------
       12                     1 file
$ python script.py 
hi

关于python - Python 解释器如何检测它是使用 ZIP 存档而不是源文件调用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12172593/

相关文章:

java - 部署基本的java应用程序以进行分发

c++ - Windows 下使用 C/C++ 的虚拟文件系统

python - Django:追踪 DjangoUnicodeDecodeError 错误

python - Word2Vec 词汇相似之处

python - 检查像素是否位于 opencv python 中的连接组件内

javascript - 在javascript中解压字符串

command-line - 如何从命令行更新巨大的 zip 存档,删除所有已删除的文件?

ruby - 给定一个 ruby​​ 脚本如何弄清楚它依赖于什么?

python - 跨服务器分发代码的最佳方式是什么?

python - python中变量变化的回调