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)