ZIP файл и избежать структуры каталогов
У меня есть скрипт Python, который new.txt
файл (new.txt
).
tofile = "/root/files/result/"+file
targetzipfile = new.zip # This is how I want my zip to look like
zf = zipfile.ZipFile(targetzipfile, mode='w')
try:
#adding to archive
zf.write(tofile)
finally:
zf.close()
Когда я делаю это, я получаю zip файл. Но когда я пытаюсь разархивировать файл, я получаю текстовый файл внутри серии каталогов, соответствующих пути к файлу, т.е. я вижу папку с именем root
в каталоге result
и больше каталогов в нем, т.е.
/root/files/result/new.zip
и когда я распаковываю new.zip
меня есть структура каталогов, которая выглядит как
/root/files/result/root/files/result/new.txt.
Есть ли способ, которым я могу заархивировать так, что когда я распаковываю, я получаю только new.txt
.
Другими словами, у меня есть /root/files/result/new.zip
и когда я распаковываю new.zip
, он должен выглядеть следующим образом
/root/files/results/new.txt
Ответы
Ответ 1
Метод zipfile.write()
принимает необязательный аргумент arcname
, который указывает, что имя файла должно находиться внутри zipfile
Я думаю, вам нужно сделать изменения для адресата, иначе он будет дублировать каталог. Используйте: arcname
, чтобы избежать этого. попробуйте вот так:
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")
Ответ 2
Ознакомьтесь с документацией для Zipfile.write.
ZipFile.write(filename [, arcname [, compress_type]]) Запишите файл named filename в архив, присвоив ему имя архива arcname (by default, это будет то же самое, что и имя файла, но без буквы диска и с удаленными ведущими разделителями пути)
https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.write
Попробуйте следующее:
import zipfile
import os
filename = 'foo.txt'
# Using os.path.join is better than using '/' it is OS agnostic
path = os.path.join(os.path.sep, 'tmp', 'bar', 'baz', filename)
zip_filename = os.path.splitext(filename)[0] + '.zip'
zip_path = os.path.join(os.path.dirname(path), zip_filename)
# If you need exception handling wrap this in a try/except block
with zipfile.ZipFile(zip_path, 'w') as zf:
zf.write(path, zip_filename)
Суть в том, что если вы не укажете имя архива, имя файла будет использоваться как имя архива и будет содержать полный путь к файлу.
Ответ 3
zf.write(tofile)
изменить
zf.write(tofile, zipfile_dir)
например
zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")
Ответ 4
Чтобы проиллюстрировать наиболее четко,
Структура каталогов :
/Users
└── /user
. ├── /pixmaps
. │ ├── pixmap_00.raw
. │ ├── pixmap_01.raw
│ ├── /jpeg
│ │ ├── pixmap_00.jpg
│ │ └── pixmap_01.jpg
│ └── /png
│ ├── pixmap_00.png
│ └── pixmap_01.png
├── /docs
├── /programs
├── /misc
.
.
.
Каталог интересов: /Пользователи/пользователь/pixmaps
Первый attemp
import os
import zipfile
TARGET_DIRECTORY = "/Users/user/pixmaps"
ZIPFILE_NAME = "CompressedDir.zip"
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
outZipFile.write(filepath)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
Структура файла ZIP:
CompressedDir.zip
.
└── /Users
└── /user
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
Избегать полного пути к каталогу
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
# The root directory within the ZIP file.
rootdir = os.path.basename(directory)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
# Write the file named filename to the archive,
# giving it the archive name 'arcname'.
filepath = os.path.join(dirpath, filename)
parentpath = os.path.relpath(filepath, directory)
arcname = os.path.join(rootdir, parentpath)
outZipFile.write(filepath, arcname)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
Структура файла ZIP:
CompressedDir.zip
.
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
Ответ 5
Вы можете изолировать только имя файла ваших исходных файлов, используя:
name_file_only= name_full_path.split(os.sep)[-1]
Например, если name_full_path
- это /root/files/results/myfile.txt
, тогда name_file_only
будет myfile.txt
. Чтобы заархивировать myfile.txt в корень архива zf
, вы можете использовать:
zf.write(name_full_path, name_file_only)