编辑:
下面的代码适用于python 2.7,但不适用于3.6(有点神秘,今天晚上早些时候它似乎可以工作):
$ cat zipf.py
from __future__ import print_function
from zipfile import ZipFile, ZipInfo
with ZipFile("out.zip", 'w') as zf:
content = "content"
info = ZipInfo()
info.filename = "file.txt"
info.flag_bits = 0x800
# don't set info.file_size here: zf.writestr() does that
zf.writestr(info, content)
with open('out.zip', 'rb') as stream:
byteseq = stream.read(8)
for i in byteseq:
if isinstance(i, str): i = ord(i)
print('{:02x}'.format(i), end=' ')
print()
运行如下:
$ python2.7 zipf.py
50 4b 03 04 14 00 00 08
但是:
$ python3.6 zipf.py
50 4b 03 04 14 00 00 00
当然有可能
制作
在创建
info
条目。但是,你必须避免
writestr
,而这只适用于Python3.6(而且似乎有点滥用):
from __future__ import print_function
from zipfile import ZipFile, ZipInfo
with ZipFile("out.zip", 'w') as zf:
info = ZipInfo()
info.filename = "file.txt"
content = "content"
if not isinstance(content, bytes):
content = content.encode('utf8')
info.file_size = len(content)
with zf.open(info, 'w') as stream:
info.flag_bits = 0x800
stream.write(content)
with open('out.zip', 'rb') as stream:
byteseq = stream.read(8)
for i in byteseq:
if isinstance(i, str): i = ord(i)
print('{:02x}'.format(i), end=' ')
print()
可能是3.6重置了所有
info.flag_bits
(通过内部
open
这是不正确的,尽管我并不清楚。
原始答案如下
我无法重现,但如果文件名为unicode,并且ascii编码失败,则设置标志位中的位11是正确的:
def _encodeFilenameFlags(self):
if isinstance(self.filename, unicode):
try:
return self.filename.encode('ascii'), self.flag_bits
except UnicodeEncodeError:
return self.filename.encode('utf-8'), self.flag_bits | 0x800
else:
return self.filename, self.flag_bits
(python 2.7 zipfile.py源代码)或:
def _encodeFilenameFlags(self):
try:
return self.filename.encode('ascii'), self.flag_bits
except UnicodeEncodeError:
return self.filename.encode('utf-8'), self.flag_bits | 0x800
(python 3.6zipfile.py源代码)。
要获得位集,您需要一个不能直接用ascii编码的文件名,例如:
info.filename = u"sch\N{latin small letter o with diaeresis}n" # "file.txt"
(此符号适用于Python2.7和3.6)。
我试图在创建zipinfo对象后通过设置标志来强制启用此位,但在_open_to_write()中它被重置回0x00。
如果我补充说:
info.filename = "file.txt"
info.flag_bits |= 0x0800
(刚将文件名设置为
u"schön"
)在python 2.7或3.6下运行,我得到了头文件中的位集(当然zip目录中的文件名变回
file.txt
)