10

フォルダー内のすべてのコンテンツを圧縮するプログラムがあります。私はこのコードを書きませんでしたが、オンラインのどこかで見つけて使用しています。たとえば、 C:/folder1/folder2/folder3/ などのフォルダーを圧縮するつもりです。folder3 とそのすべての内容を folder3.zip というファイルに圧縮したいと思います。以下のコードでは、zip すると、folder3.zip の内容は folder1/folder2/folder3/and ファイルになります。パス全体を圧縮するのではなく、目的のサブフォルダー (この場合は folder3) だけを圧縮したいのです。os.chdir などをいくつか試しましたが、うまくいきませんでした。

def makeArchive(fileList, archive):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    try:
        a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

        for f in fileList:
            print "archiving file %s" % (f)
            a.write(f)
        a.close()
        return True
    except: return False 

def dirEntries(dir_name, subdir, *args):
    # Creates a list of all files in the folder
    '''Return a list of file names found in directory 'dir_name'
    If 'subdir' is True, recursively access subdirectories under 'dir_name'.
    Additional arguments, if any, are file extensions to match filenames. Matched
        file names are added to the list.
    If there are no additional arguments, all files found in the directory are
        added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', False, 'txt', 'py')
        Only files with 'txt' and 'py' extensions will be added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', True)
        All files and all the files in subdirectories under H:\TEMP will be added
        to the list. '''

    fileList = []
    for file in os.listdir(dir_name):
        dirfile = os.path.join(dir_name, file)
        if os.path.isfile(dirfile):
            if not args:
                fileList.append(dirfile)
            else:
                if os.path.splitext(dirfile)[1][1:] in args:
                    fileList.append(dirfile)
            # recursively access file names in subdirectories
        elif os.path.isdir(dirfile) and subdir:
            print "Accessing directory:", dirfile
            fileList.extend(dirEntries(dirfile, subdir, *args))
    return fileList

これは で呼び出すことができますmakeArchive(dirEntries(folder, True), zipname)

この問題を解決する方法についてのアイデアはありますか? 私はWindows OSとpython 25を使用しています。python 2.7にはshutil make_archiveがあり、役立つことはわかっていますが、2.5で作業しているため、別のソリューションが必要です:-/

4

2 に答える 2

21

相対パスを使用するarcname引数を与える必要があります。ZipFile.write()これを行うには、削除するルート パスを に指定しmakeArchive()ます。

def makeArchive(fileList, archive, root):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

    for f in fileList:
        print "archiving file %s" % (f)
        a.write(f, os.path.relpath(f, root))
    a.close()

これを次のように呼び出します。

makeArchive(dirEntries(folder, True), zipname, folder)

ブランケットを外してしまいましtry:except:; ここではそれは役に立たず、知りたい問題を隠すだけです。

このos.path.relpath()関数は に対する相対パスを返し、rootそのルート パスをアーカイブ エントリから効果的に削除します。

Python 2.5 では、このrelpath関数は使用できません。この特定のユースケースでは、次の置き換えが機能します。

def relpath(filename, root):
    return filename[len(root):].lstrip(os.path.sep).lstrip(os.path.altsep)

そして使用:

a.write(f, relpath(f, root))

上記の関数は、 で始まることが保証されているrelpath()特定のケースでのみ機能することに注意してください。Windows では、一般的なケースはもっと複雑です。可能であれば、Python 2.6 以降にアップグレードすることを強くお勧めします。filepathrootrelpath()

于 2013-01-21T13:04:54.063 に答える
2

ZipFile.writeにはオプションの引数がありますarcname。これを使用して、パスの一部を削除します。

メソッドを次のように変更できます。

def makeArchive(fileList, archive, path_prefix=None):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    try:
        a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

        for f in fileList:
            print "archiving file %s" % (f)
            if path_prefix is None:
                a.write(f)
            else:
                a.write(f, f[len(path_prefix):] if f.startswith(path_prefix) else f)
        a.close()
        return True
    except: return False 

ただし、os.path を使用した Martijn のアプローチは、はるかにエレガントです。

于 2013-01-21T13:02:56.943 に答える