Создать .zip в Python?
Я пытаюсь создать функцию в моем script, которая застегивает содержимое данного исходного каталога (src
) в zip файл (dst
). Например, zip('/path/to/dir', '/path/to/file.zip')
, где /path/to/dir
- это каталог, а /path/to/file.zip
еще не существует. Я не хочу заархивировать саму директорию, это делает всю разницу в моем случае. Я хочу заархивировать файлы (и поддиры) в каталоге. Это то, что я пытаюсь:
def zip(src, dst):
zf = zipfile.ZipFile("%s.zip" % (dst), "w")
for dirname, subdirs, files in os.walk(src):
zf.write(dirname)
for filename in files:
zf.write(os.path.join(dirname, filename))
zf.close()
Это создает почтовый индекс, по существу /
. Например, если я zipped /path/to/dir
, извлечение zip создает каталог с "path" в нем, с "to" в этом каталоге и т.д.
Есть ли у кого-нибудь функция, которая не вызывает этой проблемы?
Я не могу это подчеркнуть, ему требуется, чтобы zip файлы в каталоге, а не сама directoy.
Ответы
Ответ 1
Метод zipfile.write()
принимает необязательный аргумент arcname
который указывает, что имя файла должно находиться внутри zip файла.
Вы можете использовать это, чтобы удалить путь до src
в начале. Здесь я
используйте os.path.abspath()
, чтобы убедиться, что как src
, так и
filename, возвращаемое os.walk()
, имеет общий префикс.
#!/usr/bin/env python2.7
import os
import zipfile
def zip(src, dst):
zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
abs_src = os.path.abspath(src)
for dirname, subdirs, files in os.walk(src):
for filename in files:
absname = os.path.abspath(os.path.join(dirname, filename))
arcname = absname[len(abs_src) + 1:]
print 'zipping %s as %s' % (os.path.join(dirname, filename),
arcname)
zf.write(absname, arcname)
zf.close()
zip("src", "dst")
С такой структурой каталогов:
src
└── a
├── b
│ └── bar
└── foo
script печатает:
zipping src/a/foo as a/foo
zipping src/a/b/bar as a/b/bar
И содержимое результирующего zip файла:
Archive: dst.zip
Length Date Time Name
-------- ---- ---- ----
0 01-28-13 11:36 a/foo
0 01-28-13 11:36 a/b/bar
-------- -------
0 2 files
Ответ 2
Используйте параметр arcname
, чтобы управлять именем/путем в zip файле.
Например, для zip файла, содержащего только файлы, нет каталогов:
zf.write(os.path.join(dirname, filename), arcname=filename)
Или создать новый каталог внутри zip файла:
zf.write(os.path.join(dirname, filename), arcname=os.path.join("my_zip_dir", filename))
Ответ 3
Из того, что я могу сказать, вы близки. Вы можете использовать dirname
и basename
, чтобы убедиться, что вы захватываете правильное имя пути:
>>> os.path.dirname("/path/to/dst")
'/path/to'
>>> os.path.basename("/path/to/dst")
'dst'
Затем, используя chdir
, вы можете убедиться, что находитесь в родительском каталоге, поэтому пути относительны.
def zip(src, dst):
parent = os.path.dirname(dst)
folder = os.path.basename(dst)
os.chdir(parent):
for dirname, subdirs, filenames in os.walk(folder):
...
Это создает:
dst/a.txt
dst/b
dst/b/c.txt
...etc...
Если вы не хотите включать имя "dst", вы можете просто сделать os.chdir(dst)
, а затем os.walk('.')
.
Надеюсь, что это поможет.