web-dev-qa-db-ja.com

pythonを使用してZipファイルにフォルダーを追加する

Zipファイルを作成したい。 Zipファイルにフォルダーを追加し、そのフォルダーに一連のファイルを追加します。

だから私はファイルが入った単一のフォルダを持つZipファイルになりたいです。

Zipファイルなどにフォルダを作成するのが悪い習慣なのかどうかはわかりませんが、Googleはこの件について何も教えてくれません。

私はこれから始めました:

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);

から取得: http://mail.python.org/pipermail/python-list/2006-August/396166.html

これにより、すべてのフォルダーが削除され、ターゲットフォルダー(およびそのサブフォルダー)内のすべてのファイルが単一のZipファイルに配置されます。フォルダー全体を追加することはできませんでした。

MyZipFile.writeのフォルダーへのパスをフィードすると、

IOError:[Errno 13]許可が拒否されました: '..\packed\bin'

どんな助けも大歓迎です。

関連質問: python(バージョン2.5)? を使用してフォルダーのコンテンツを圧縮するにはどうすればよいですか?)==

43
Mizipzor

OK、あなたが望むものを理解した後、zipfile.writeの2番目の引数を使用するのと同じくらい簡単です。

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

test.pydirというディレクトリに抽出されるzipファイルを作成します

編集:Zipファイルに空のディレクトリを作成する必要がありました:それは可能です。上記のコードがzipファイルからtest.pyファイルを削除すると、ファイルはなくなりますが、空のディレクトリは残ります。

45
RSabet

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に配置されます。

55
Gideon

Zipファイルにはディレクトリ構造はありません。パス名とその内容の束だけがあります。これらのパス名は、架空のルートフォルダー(Zipファイル自体)に対して相対的でなければなりません。 「../」プレフィックスは、Zipファイルでは定義された意味を持ちません。

ファイルaがあり、Zipファイル内の「フォルダー」に保存することを検討してください。 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

Zipファイルにemptyフォルダーを含めることを許可するZip実装を知りません。回避策(抽出時に無視する必要のあるZip "フォルダ"にdummyファイル名を保存する)を考えることはできますが、実装間で移植性はありません。

14
tzot
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)

ご覧のとおり、動作します。アーカイブも大丈夫です。これは、フォルダー全体を圧縮できる再帰関数です。唯一の問題は、空のフォルダーが作成されないことです。

乾杯。

8
havok-cr

以下は、ディレクトリ全体をzipファイルに圧縮するためのコードです。

これは、WindowsとLinuxの両方でZipファイルを作成しても問題ないようです。出力ファイルは、Windows(組み込みの圧縮フォルダー機能、WinZip、および7-Zip)およびlinuxで適切に抽出されるようです。ただし、Zipファイル内の空のディレクトリは厄介な問題のようです。以下の解決策は機能しているようですが、Linuxでの「zipinfo」の出力が懸念されます。また、Zipアーカイブ内の空のディレクトリに対してディレクトリのアクセス許可が正しく設定されていません。これには、さらに詳細な調査が必要と思われます。

this velocity review thread および this python mailing list thread から情報を得ました。

この関数は、親ディレクトリを持たないか、親ディレクトリを1つだけ持つZipアーカイブにファイルを配置するように設計されているため、Zipアーカイブパス内にファイルシステムパスの先頭のディレクトリは含まれません。これは一般に、ディレクトリを取得して、それを異なる場所に抽出できるZipファイルにしたい場合です。

キーワード引数:

dirPath-アーカイブするディレクトリへの文字列パス。これは唯一の必須引数です。絶対または相対のどちらでもかまいませんが、Zipアーカイブに含まれる先頭ディレクトリは1つまたは0個だけです。

zipFilePath-出力Zipファイルへの文字列パス。これは絶対パスでも相対パスでもかまいません。 Zipファイルが既に存在する場合、更新されます。そうでない場合は、作成されます。ゼロから置き換える場合は、この関数を呼び出す前に削除してください。 (デフォルトはdirPath + ".Zip"として計算されます)

includeDirInZip-最上位ディレクトリをアーカイブに含めるか省略するかを示すブール値。 (デフォルトはTrue)

(StackOverflowは、pythonを三重引用符付き文字列できれいに印刷できないため、ここでdoc文字列を投稿テキストに変換しました)

#!/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引数に複数の先行ディレクトリがある場合、デフォルトでは最後のディレクトリのみが含まれることに注意してください。 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
Peter Lyons

ここにフォルダを圧縮するために使用する私の機能があります:

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

Info-Zipで作成された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

インポートを追加した後、コードは正常に実行されます。スクリプトをどのように呼び出しますか。「..\packed\bin」ディレクトリのフォルダ構造を教えてください。

次の引数を使用してコードを呼び出しました。

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

`

2
RSabet

この便利な機能に感謝します!私も助けを探していたので、とても便利だと思いました。ただし、それを少し変更して、

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

だろう

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

「C:\ folder\path\notWanted\to\Zip\Example」にあるフォルダー「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
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

私が実行した編集済みコードを示します。メーリングリストから取得した上記のコードに基づいています。インポートを追加し、メインルーチンを作成しました。また、コードを短くするために、出力ファイル名をいじるのを切り取りました。

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