python zipfile.ZipFile не добавляет файлы в каталог [duplicate]

ArrayList не являются безопасными типа, тогда как List<T> безопасны по типу. Простой:).

39
задан Community 23 May 2017 в 12:17
поделиться

12 ответов

после добавления некоторых импортных кодов для меня отлично работает, как вы называете скрипт, возможно, вы могли бы рассказать нам о структуре папок каталога «.. \ упакованный \ bin».

Я назвал ваш код следующими аргументами:

planName='test.zip'
files=['z.py',]
folders=['c:\\temp']
(success,filename)=createZipFile(planName,files,folders)

`

41
ответ дан RSabet 19 August 2018 в 19:21
поделиться
  • 1
    Вызов кода с этими аргументами приведет к созданию файла test.zip, содержащего как z.py, так и каждый файл в c: \ temp, но без папок. Просто zip со многими файлами. Но я нашел ответ в соответствующем вопросе, который, кажется, делает то, что я хочу. Идти дальше, чтобы посмотреть на это. – Mizipzor 19 January 2009 в 21:32
  • 2
    Да, может быть, вы могли бы привести пример, как вызвать код, поэтому ваша ошибка возникает. – RSabet 19 January 2009 в 22:27
  • 3
    Ошибок нет. Код создает zip-файл и все такое. Проблема заключается в том, что я хочу, чтобы папки создавались при распаковке файла или в zip-файле, содержащем папки, в зависимости от того, как вы смотрите на него. – Mizipzor 19 January 2009 в 23:07
  • 4
    Спасибо, теперь я понимаю! – RSabet 19 January 2009 в 23:10
  • 5
    Да, это похоже на то, что мне нужно. Прочитав комментарий ΤΖΩΤ comment, я теперь понимаю, как «папки» в zip-файлах. И я нашел код в связанном вопросе, который также сделал то, что я хочу, но я не понимал, как это сделать. Скорее экспериментируйте и возвращайтесь, чтобы опубликовать код, который я фактически использовал. :) – Mizipzor 19 January 2009 в 23:29
  • 6
    И что лучше, так же, как и с tarfile, если вы когда-нибудь создадите один :) в tarfile параметр называется arcname для имени архива. – Matthieu M. 31 March 2010 в 18:11
  • 7
    Для этого для работы на платформе вам необходимо использовать os.path.join («dir», «test.py») – ktec 17 June 2012 в 22:40
  • 8
    Для самих записей каталога (включая пустые каталоги), я думаю, вы можете просто передать их в .write, как если бы они были файлами. Но используйте zipfile.ZIP_STORED для каталогов. Я добавил ответ с более подробной информацией. – z0r 18 August 2013 в 06:04
  • 9
    понравилось, как вы это делаете ... я использовал цикл for, который занимает слишком много времени – Pythonizer 31 May 2014 в 14:36
42
ответ дан RSabet 31 October 2018 в 05:35
поделиться
import zipfile
import os


class ZipUtilities:

    def toZip(self, file, filename):
        zip_file = zipfile.ZipFile(filename, 'w')
        if os.path.isfile(file):
                    zip_file.write(file)
            else:
                    self.addFolderToZip(zip_file, file)
        zip_file.close()

    def addFolderToZip(self, zip_file, folder): 
        for file in os.listdir(folder):
            full_path = os.path.join(folder, file)
            if os.path.isfile(full_path):
                print 'File added: ' + str(full_path)
                zip_file.write(full_path)
            elif os.path.isdir(full_path):
                print 'Entering folder: ' + str(full_path)
                self.addFolderToZip(zip_file, full_path)

def main():
    utilities = ZipUtilities()
    filename = 'TEMP.zip'
    directory = 'TEMP'
    utilities.toZip(directory, filename)

main()

Я запускаю:

python tozip.py

Это журнал:

havok@fireshield:~$ python tozip.py

File added: TEMP/NARF (7ª copia)
Entering folder: TEMP/TEMP2
File added: TEMP/TEMP2/NERF (otra copia)
File added: TEMP/TEMP2/NERF (copia)
File added: TEMP/TEMP2/NARF
File added: TEMP/TEMP2/NARF (copia)
File added: TEMP/TEMP2/NARF (otra copia)
Entering folder: TEMP/TEMP2/TEMP3
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL (copia)
File added: TEMP/TEMP2/NERF
File added: TEMP/NARF (copia) (otra copia)
File added: TEMP/NARF (copia) (copia)
File added: TEMP/NARF (6ª copia)
File added: TEMP/NERF (copia) (otra copia)
File added: TEMP/NERF (4ª copia)
File added: TEMP/NERF (otra copia)
File added: TEMP/NERF (3ª copia)
File added: TEMP/NERF (6ª copia)
File added: TEMP/NERF (copia)
File added: TEMP/NERF (5ª copia)
File added: TEMP/NARF (8ª copia)
File added: TEMP/NARF (3ª copia)
File added: TEMP/NARF (5ª copia)
File added: TEMP/NERF (copia) (3ª copia)
File added: TEMP/NARF
File added: TEMP/NERF (copia) (copia)
File added: TEMP/NERF (8ª copia)
File added: TEMP/NERF (7ª copia)
File added: TEMP/NARF (copia)
File added: TEMP/NARF (otra copia)
File added: TEMP/NARF (4ª copia)
File added: TEMP/NERF
File added: TEMP/NARF (copia) (3ª copia)

Как вы можете видеть, он работает, архив тоже в порядке. Это рекурсивная функция, которая может застегивать всю папку. Единственная проблема заключается в том, что она не создает пустую папку.

Приветствия.

7
ответ дан Community 19 August 2018 в 19:21
поделиться

Вы также можете использовать shutil

import shutil

zip_name = 'path\to\zip_file'
directory_name = 'path\to\directory'

# Create 'path\to\zip_file.zip'
shutil.make_archive(zip_name, 'zip', directory_name)

. Это поместит всю папку в zip.

50
ответ дан Darthfett 19 August 2018 в 19:21
поделиться
  • 1
    Он доступен только на Python 2.7+ – jfs 13 December 2011 в 23:24
  • 2
    Интересно, что этот метод добавляет .zip к вашему desired_zipfile_name_no, даже если он уже имеет расширение .zip. Затем он возвращает полный путь, на который он написал, с новым расширением. (Вы можете использовать другие форматы, кроме zip, я ожидаю, что он добавит их расширение также.) – zekel 26 January 2012 в 21:14
  • 3
    Он не сохраняет символические ссылки – ppetraki 6 March 2014 в 19:14
  • 4
    Это выглядит хорошо, но я не могу изменить путь назначения к zipped-файлу, я пытаюсь добавить dir в качестве 4-го параметра, но он не работает. – Summer Sun 24 March 2016 в 09:01
  • 5
    благодаря! Это больше похоже на это. Я не понимаю, как ZipFile.write (path, arcname) просто игнорирует содержимое path, если это папка и просто создает пустую папку в zip. Какая польза от этого?!?! Почему это стандартное поведение!?!? : | – ewerybody 23 June 2016 в 13:52

здесь моя функция, которую я использую, чтобы застегнуть папку:

import os
import os.path
import zipfile

def zip_dir(dirpath, zippath):
    fzip = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
    basedir = os.path.dirname(dirpath) + '/' 
    for root, dirs, files in os.walk(dirpath):
        if os.path.basename(root)[0] == '.':
            continue #skip hidden directories        
        dirname = root.replace(basedir, '')
        for f in files:
            if f[-1] == '~' or (f[0] == '.' and f != '.htaccess'):
                #skip backup files and all hidden files except .htaccess
                continue
            fzip.write(root + '/' + f, dirname + '/' + f)
    fzip.close()
3
ответ дан Dmitry Nedbaylo 19 August 2018 в 19:21
поделиться

Сохраняет отредактированный код, который я запускал. Он основан на приведенном выше коде, взятом из списка рассылки. Я добавил импорт и сделал основную процедуру.

#!/usr/bin/env python

import os, zipfile, glob, sys

def addFolderToZip(myZipFile,folder):
    folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
    for file in glob.glob(folder+"/*"):
            if os.path.isfile(file):
                print file
                myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
            elif os.path.isdir(file):
                addFolderToZip(myZipFile,file)

def createZipFile(filename,files,folders):
    myZipFile = zipfile.ZipFile( filename, "w" ) # Open the zip file for writing 
    for file in files:
        file = file.encode('ascii') #convert path to ascii for ZipFile Method
        if os.path.isfile(file):
            (filepath, filename) = os.path.split(file)
            myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )

    for folder in  folders:   
        addFolderToZip(myZipFile,folder)  
    myZipFile.close()
    return (1,filename)

if __name__=="__main__":
    #put everything in sys.argv[1] in out.zip, skip files
    print createZipFile("out.zip", [], sys.argv[1])

На работе, в моем окне Windows, этот код работал нормально, но не создавал никаких «папок» в zip-файле. По крайней мере, я это помню. Теперь у себя дома, на моем Linux-сервере, созданный zip-файл кажется плохим:

$ unzip -l out.zip 
Archive:  out.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of out.zip or
        out.zip.zip, and cannot find out.zip.ZIP, period.

Я не знаю, случайно ли я сломал код, я думаю, что это то же самое. Проблемы с кроссплатформой? В любом случае, это не связано с моим первоначальным вопросом; получение папок в zip-файле. Просто хотел опубликовать код, который я на самом деле выполнял, а не код, на котором я основывал свой код.

0
ответ дан Mizipzor 19 August 2018 в 19:21
поделиться
  • 1
    это новый код? Тогда это должен быть новый вопрос. Если вы не обновите свой вопрос новыми фактами. Это не кажется ответом. – S.Lott 20 January 2009 в 04:20
  • 2
    sys.argv[1] - строка. Вы передаете его как folders. Когда вы перебираете строку, вы получаете по одной букве за раз. – jfs 20 January 2009 в 05:27
  • 3
    Задавайте новые вопросы как вопросы, а не ответы. – jfs 20 January 2009 в 05:30

Ниже приведен некоторый код для zipping полного каталога в zip-файл.

Кажется, что он работает ОК, создавая zip-файлы как в окнах, так и в linux. Выходные файлы, похоже, правильно извлекаются на окнах (встроенная функция сжатых папок, WinZip и 7-Zip) и Linux. Однако пустые каталоги в zip-файле кажутся сложной проблемой. Решение, похоже, работает, но выход «zipinfo» в linux имеет отношение. Кроме того, права каталога не установлены правильно для пустых каталогов в zip-архиве.

Я получил некоторую информацию из , эту скорость просматривает поток и этот поток рассылки списка python .

Обратите внимание, что эта функция предназначена для размещения файлов в zip-архиве без родительского каталога или только с одним родительским каталогом, поэтому он будет обрезать любые ведущие каталоги в путях файловой системы и не включать их в пути zip-архива. Это обычно происходит, когда вы хотите просто взять каталог и сделать его в zip-файл, который можно извлечь в разных местах.

Аргументы ключевого слова:

dirPath - строковый путь к каталогу для архивирования. Это единственный требуемый аргумент. Он может быть абсолютным или относительным, но только один или нулевой ведущий каталог будет включен в zip-архив.

zipFilePath - строковый путь к выходному zip-файлу. Это может быть абсолютный или относительный путь. Если zip-файл уже существует, он будет обновлен. Если нет, он будет создан. Если вы хотите заменить его с нуля, удалите его до вызова этой функции. (по умолчанию вычисляется как dirPath + ".zip")

includeDirInZip - boolean, указывающий, должен ли каталог верхнего уровня быть включен в архив или опущен. (по умолчанию True)

(обратите внимание, что StackOverflow, похоже, не умеет печатать мой питон с тройными кавычками, поэтому я просто конвертировал мои строки документа в текст сообщения здесь)

#!/usr/bin/python
import os
import zipfile

def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=True):

    if not zipFilePath:
        zipFilePath = dirPath + ".zip"
    if not os.path.isdir(dirPath):
        raise OSError("dirPath argument must point to a directory. "
            "'%s' does not." % dirPath)
    parentDir, dirToZip = os.path.split(dirPath)
    #Little nested function to prepare the proper archive path
    def trimPath(path):
        archivePath = path.replace(parentDir, "", 1)
        if parentDir:
            archivePath = archivePath.replace(os.path.sep, "", 1)
        if not includeDirInZip:
            archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
        return os.path.normcase(archivePath)

    outFile = zipfile.ZipFile(zipFilePath, "w",
        compression=zipfile.ZIP_DEFLATED)
    for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath):
        for fileName in fileNames:
            filePath = os.path.join(archiveDirPath, fileName)
            outFile.write(filePath, trimPath(filePath))
        #Make sure we get empty directories as well
        if not fileNames and not dirNames:
            zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/")
            #some web sites suggest doing
            #zipInfo.external_attr = 16
            #or
            #zipInfo.external_attr = 48
            #Here to allow for inserting an empty directory.  Still TBD/TODO.
            outFile.writestr(zipInfo, "")
    outFile.close()

Вот несколько примеров использования. Обратите внимание, что если ваш аргумент dirPath имеет несколько ведущих каталогов, по умолчанию будет включен только LAST. Pass includeDirInZip = False, чтобы опустить все ведущие каталоги.

zipdir("foo") #Just give it a dir and get a .zip file
zipdir("foo", "foo2.zip") #Get a .zip file with a specific file name
zipdir("foo", "foo3nodir.zip", False) #Omit the top level directory
zipdir("../test1/foo", "foo4nopardirs.zip")
4
ответ дан Mu Mind 19 August 2018 в 19:21
поделиться

Большое спасибо за эту полезную функцию! Я нашел его очень полезным, так как искал помощи. Однако, возможно, было бы полезно немного изменить его, чтобы

basedir = os.path.dirname(dirpath) + '/'

был

basedir = os.path.dirname(dirpath + '/')

. Потому что нашел, что если я хочу застегнуть папку «Пример», находится в папке 'C: \ folder \ path\notWanted \ to \ zip \ Example',

Я получил в Windows:

dirpath = 'C:\folder\path\notWanted\to\zip\Example'
basedir = 'C:\folder\path\notWanted\to\zip\Example/'
dirname = 'C:\folder\path\notWanted\to\zip\Example\Example\Subfolder_etc'

Но я полагаю, что ваш код должен давать

dirpath = 'C:\folder\path\notWanted\to\zip\Example'
basedir = 'C:\folder\path\notWanted\to\zip\Example\'
dirname = '\Subfolder_etc'
0
ответ дан note 19 August 2018 в 19:21
поделиться
import os
import zipfile

zf = zipfile.ZipFile("file.zip", "w")
for file in os.listdir(os.curdir):
    if not file.endswith('.zip') and os.path.isfile(os.curdir+'/'+file):
        print file
        zf.write(file)
    elif os.path.isdir(os.curdir+'/'+file):
        print f
        for f in os.listdir(os.curdir+'/'+file):
            zf.write(file+'\\'+f)
zf.close()
0
ответ дан sohom 19 August 2018 в 19:21
поделиться
  • 1
    Это не будет работать для вложенных подкаталогов: если у вас есть dir, содержащий subdir, содержащий file.txt, вам не повезло. Лучше создать рекурсивную функцию. – MarSoft 28 July 2017 в 01:20

Почтовый файл не имеет структуры каталогов, он просто содержит пустые имена и их содержимое. Эти пути должны относиться к воображаемой корневой папке (самому ZIP-файлу). Префикс «../» не имеет определенного значения в zip-файле.

У вас есть файл a, и вы хотите сохранить его в «папке» внутри zip-файла. Все, что вам нужно сделать, это префикс имени файла с именем папки при хранении файла в zip-файле:

zipi= zipfile.ZipInfo()
zipi.filename= "folder/a" # this is what you want
zipi.date_time= time.localtime(os.path.getmtime("a"))[:6]
zipi.compress_type= zipfile.ZIP_DEFLATED
filedata= open("a", "rb").read()

zipfile1.writestr(zipi, filedata) # zipfile1 is a zipfile.ZipFile instance

Я не знаю никаких реализаций ZIP, позволяющих включить empty в ZIP-файле. Я могу подумать об обходном пути (сохраняя имя файла dummy в zip-папке, которое следует игнорировать при извлечении), но не переносимо для всех реализаций.

11
ответ дан tzot 19 August 2018 в 19:21
поделиться
  • 1
    Понимаю. Поэтому, если я правильно понял, zip-файл не содержит никаких папок. Но если файл имеет разделитель путей в своем имени, он отображается как файл в папке в большинстве архивных менеджеров? И будет ли он создан таким образом, когда архив распакуется? – Mizipzor 19 January 2009 в 23:09
  • 2
    Верный. Это сложно сделать, поскольку средства архивации корректно удаляют разделители путей в именах файлов. Однако вы, python-программа, можете форсировать неограниченные имена. – S.Lott 19 January 2009 в 23:25

Когда вы хотите создать пустую папку, вы можете сделать это следующим образом:

    storage = api.Storage.open("empty_folder.zip","w")
    res = storage.open_resource("hannu//","w")
    storage.close()

Папка не отображается в файле winextractor, но когда вы ее извлекаете, она отображается.

-2
ответ дан user 19 August 2018 в 19:21
поделиться

Если вы посмотрите на zip-файл, созданный с помощью Info-ZIP, вы увидите, что каталоги действительно перечислены:

$ zip foo.zip -r foo
  adding: foo/ (stored 0%)
  adding: foo/foo.jpg (deflated 84%)
$ less foo.zip
  Archive:  foo.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2013-08-18 14:32 00000000  foo/
  476320  Defl:N    77941  84% 2013-08-18 14:31 55a52268  foo/foo.jpg
--------          -------  ---                            -------
  476320            77941  84%                            2 files

Обратите внимание, что запись в каталоге имеет нулевую длину и не сжата. Кажется, вы можете добиться того же самого с Python, написав каталог по имени, но вынуждая его не использовать сжатие.

if os.path.isdir(name):
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_STORED)
else:
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)

Возможно, стоит убедиться, что arcname завершен в / .

2
ответ дан z0r 19 August 2018 в 19:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: