Dodawanie folderów do pliku zip za pomocą Pythona

Chcę utworzyć plik zip. Dodaj folder do pliku zip, a następnie dodaj kilka plików do tego folderu.

Więc chcę skończyć z plikiem zip z pojedynczym folderem z plikami w.

Nie wiem, czy to zła praktyka, aby mieć foldery w plikach zip, czy coś, ale google nie daje mi nic na ten temat.

Zacząłem od tego:

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):
    curTime=strftime("__%Y_%m_%d", time.localtime())
    filename=filename+curTime;
    print filename
    zipFilename=utils.getFileName("files", filename+".zip")
    myZipFile = zipfile.ZipFile( zipFilename, "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,zipFilename)


(success,filename)=createZipFile(planName,files,folders);

Pochodzi z: http://mail.python.org/pipermail/python-list/2006-August/396166.html

Który się pozbawia wszystkie foldery i umieszcza wszystkie pliki w folderze docelowym (i jego podfoldery) w jednym pliku zip. Nie mogłem dodać całego folderu.

Jeśli dodam ścieżkę do folderu w myZipFile.pisz, dostaję

IOError: [Errno 13] Permission denied:'..\ packed\bin '

Każda pomoc jest mile widziana.

Podobne pytanie: Jak spakować zawartość folderu używając Pythona (Wersja 2.5)?

Author: Community, 2009-01-19

12 answers

Ok, po tym jak zrozumiałem, czego chcesz, jest to tak proste, jak użycie drugiego argumentu zipfile.write, gdzie możesz użyć, co chcesz:

import zipfile
myZipFile = zipfile.ZipFile("zip.zip", "w" )
myZipFile.write("test.py", "dir\\test.py", zipfile.ZIP_DEFLATED )

Tworzy plik zipfile, w którym test.py zostanie rozpakowany do katalogu o nazwie dir

Edytuj: Kiedyś musiałem utworzyć pusty katalog w pliku zip: jest to możliwe. po powyższym kodzie wystarczy usunąć plik test.py z pliku zipfile plik zniknie, ale pusty katalog pozostanie.

 42
Author: RSabet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 11:31:00

Możesz również użyć 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)

Spowoduje to umieszczenie całego folderu w zip.

 50
Author: Gideon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 17:34:02

Plik zip nie ma struktury katalogów, ma tylko kilka ścieżek i ich zawartość. Te ścieżki powinny być względem wyimaginowanego folderu głównego (samego pliku ZIP). "../ "prefiksy nie mają zdefiniowanego znaczenia w pliku zip.

Uznaj, że masz plik, a i chcesz go przechowywać w" folderze " wewnątrz pliku zip. Wszystko, co musisz zrobić, to przedrostek nazwy pliku z nazwą folderu podczas przechowywania pliku w pliku zipfile:

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

Nie znam żadnych implementacji ZIP pozwala na umieszczenie pustego folderu w pliku ZIP. Mogę wymyślić obejście (przechowywanie dummy nazwa pliku w "folderze" zip, który powinien być ignorowany podczas ekstrakcji), ale nie Przenośne w różnych implementacjach.

 11
Author: tzot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-19 21:34:13
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()

Biegnę:

python tozip.py

To jest dziennik:

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)

Jak widać, działa, archiwum też jest ok. Jest to funkcja rekurencyjna, która może zapinać cały folder. Jedynym problemem jest to, że nie tworzy pustego folderu.

Zdrówko.
 7
Author: Community,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 14:58:24

Poniżej znajduje się kod do zamocowania całego katalogu do pliku zipfile.

To wydaje się działać OK tworzenie plików zip w systemie windows i linux. Wyjście pliki wydają się prawidłowo rozpakowywać w systemie windows (wbudowana funkcja skompresowanych folderów, WinZip i 7-Zip) oraz linux. Pojawiają się jednak puste katalogi w pliku zip być bolesnym problemem. Poniższe rozwiązanie wydaje się działać, ale wyjście z "zipinfo" na Linuksie jest niepokojące. Również uprawnienia katalogu nie są ustawione poprawnie dla pustych katalogi w archiwum zip. Wydaje się, że wymaga to trochę bardziej dogłębnych badań.

Dostałem kilka informacji z tego wątku velocity reviewsi tego wątku listy dyskusyjnej Pythona.

Zauważ, że ta funkcja jest przeznaczona do umieszczania plików w archiwum zip z albo nie ma katalogu nadrzędnego, albo tylko jeden Katalog nadrzędny, więc przycina wszelkie katalogi wiodące w ścieżkach systemu plików i nie zawierają ich wewnątrz ścieżki archiwum zip. Dzieje się tak zazwyczaj, gdy chcesz po prostu wziąć katalog i zrobić z niego plik zip, który można wyodrębnić w różnych miejsca.

Argumenty ze słowem kluczowym:

DirPath -- ścieżka łańcuchowa do katalogu do archiwum. To jedyny wymagany argument. Może być absolutny lub względny, ale tylko jeden lub zero wiodące katalogi zostaną włączone do archiwum zip.

ZipFilePath -- ścieżka do wyjściowego pliku zip. Może to być absolutna lub ścieżka względna. Jeśli plik zip już istnieje, będzie aktualizacja. Jeśli nie, zostanie stworzony. Jeśli chcesz go zastąpić od zera, usuń go przed wywołaniem tej funkcji. (domyślnie jest obliczana jako dirPath + ".zip")

IncludeDirInZip -- boolean wskazujący, czy katalog najwyższego poziomu powinien być zawarte w archiwum lub pominięte. (default True)

(zauważ, że StackOverflow zdaje się nie drukować mojego Pythona z trzy cytowane ciągi, więc właśnie przekonwertowałem moje ciągi doc na tekst posta tutaj)

#!/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()

Oto niektóre przykładowe zastosowania. Zauważ, że jeśli twój argument dirPath ma kilka wiodących katalogów, domyślnie zostanie uwzględniony tylko ostatni. Pass includeDirInZip=False aby pominąć wszystkie wiodące katalogi.

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
Author: Mu Mind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 03:14:07

Oto moja funkcja, której używam do zamykania folderu:

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
Author: Dmitry Nedbaylo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-09 17:04:44

Po dodaniu kilku importów Twój kod działa dobrze dla mnie, jak nazwać skrypt, może mógłbyś nam powiedzieć o strukturze folderów '..\packed \ bin' directory.

Nazwałem Twój kod następującymi argumentami:

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

`

 2
Author: RSabet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-19 17:47:34

Jeśli spojrzysz na plik zip utworzony za pomocą Info-ZIP, zobaczysz, że katalogi są rzeczywiście wymienione:

$ 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

Zauważ, że wpis katalogu ma zerową długość i nie jest skompresowany. Wydaje się, że można osiągnąć to samo z Pythonem, pisząc Katalog po nazwie, ale zmuszając go do nie używania kompresji.

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)

Może warto się upewnić, że arcname kończy się /.

 2
Author: z0r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-18 04:41:39

Oto edytowany kod, który uruchomiłem. Opiera się na powyższym kodzie, zaczerpniętym z listy dyskusyjnej. Dodałem import i zrobiłem główną rutynę. Wyciąłem również majstrowanie z nazwą pliku wyjściowego, aby Kod był krótszy.

#!/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])

W pracy, na moim Windows box, ten kod działał dobrze, ale nie stworzył żadnych "folderów" w pliku zipfile. Przynajmniej sobie przypominam. Teraz w domu, na moim Linuksie, utworzony plik zip wydaje się być zły:

$ 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.

Nie wiem, czy przypadkowo złamałem kod, myślę, że jego to samo. Problemy z platformą? Tak czy inaczej, nie jest związany z moim oryginalnym pytaniem; pobieranie folderów w pliku zip. Chciałem tylko dodać kod, który uruchomiłem, a nie kod, na którym bazowałem.

 0
Author: Mizipzor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-19 22:26:04

Dziękuję bardzo wery za tę przydatną funkcję! Okazało się to bardzo przydatne, ponieważ również szukałem pomocy. Jednak może przydałoby się to trochę zmienić, aby

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

Byłoby

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

Ponieważ okazało się, że jeśli chcę zip folder 'przykład', który znajduje się w 'C:\folder\path\notWanted\to\zip\Example",

Mam w 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'

Ale przypuszczam, że Twój kod powinien dać

dirpath = 'C:\folder\path\notWanted\to\zip\Example'
basedir = 'C:\folder\path\notWanted\to\zip\Example\'
dirname = '\Subfolder_etc'
 0
Author: note,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 10:17:30
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
Author: sohom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-17 19:32:24

Gdy chcesz utworzyć pusty folder, możesz to zrobić w następujący sposób:

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

Folder nie wyświetla się w winextractor, ale po rozpakowaniu jest wyświetlany.

 -2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-24 08:06:09