Zip文件和避免目录结构

73

我有一个Python脚本,用于压缩文件(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
14个回答

86
< p > zipfile.write() 方法有一个可选的 arcname 参数,用于指定文件在压缩文件中的名称。

我认为您需要对目标进行修改,否则它会重复目录。使用: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")

1
我不明白为什么需要指定arcname来避免它遍历所有父文件夹直到根目录,如果我提供了文件路径,为什么它不只考虑文件本身? - Mojimi
你可以将 arcname = absname[len(abs_src) + 1:] 更改为 arcname = os.path.basename(absname)。 - Felix Martinez

20
zf.write(tofile)

改变

zf.write(tofile, zipfile_dir)

例如

zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")

1
@user34551743,太棒了! - Mark K

14
为了更加清晰地说明,目录结构如下:
/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
      .
      .
      .

感兴趣的目录:/Users/user/pixmaps

首次尝试

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

1
在第二个程序中,我认为 outZipFile.close() 这一行应该在 if 块内。 - theoctober19th

10
在write方法中,arcname参数指定了将要被压缩文件的名称:
import os
import zipfile

# 1. Create a zip file which we will write files to
zip_file = "/home/username/test.zip"
zipf = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)

# 2. Write files found in "/home/username/files/" to the test.zip
files_to_zip = "/home/username/files/"
for file_to_zip in os.listdir(files_to_zip):

    file_to_zip_full_path = os.path.join(files_to_zip, file_to_zip)

    # arcname argument specifies what will be the name of the file inside the zipfile
    zipf.write(filename=file_to_zip_full_path, arcname=file_to_zip)

zipf.close()

2
在所有的答案中,你的是最简单的,让我很快就明白了。谢谢! - Priyansh Gupta

7
您可以使用以下方式仅隔离源文件的文件名:
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)

1
如果你有一个不同的问题,而这个问题并不存在,那么我认为你应该提出那个问题,并回答自己的问题。当其他人使用更相关的问题进行搜索时,你将会帮助到他们(甚至是未来的你自己)。 - ordonezalex

6
请查看Zipfile.write的文档。

ZipFile.write(filename[, arcname[, compress_type]]) 将名为filename的文件写入存档文件,并将其命名为arcname(默认情况下,arcname将与filename相同,但没有驱动器号并且已删除前导路径分隔符)

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)

简而言之,如果您不指定归档文件名,则文件名将用作归档文件名,并且其中将包含文件的完整路径。


5

这比预期的要简单得多,我使用参数“arcname”将模块配置为“file_to_be_zipped.txt”,因此文件夹不会出现在我的最终压缩文件中:

mmpk_zip_file = zipfile.ZipFile("c:\\Destination_folder_name\newzippedfilename.zip", mode='w', compression=zipfile.ZIP_DEFLATED)
mmpk_zip_file.write("c:\\Source_folder_name\file_to_be_zipped.txt", "file_to_be_zipped.txt")
mmpk_zip_file.close()

2
我们可以使用这个。
import os
# single File
os.system(f"cd {destinationFolder} && zip fname.zip fname") 
# directory
os.system(f"cd {destinationFolder} && zip -r folder.zip folder") 

对于我来说,这个正在正常运作。

1
请将write方法的arcname输入指定为以下内容:
tofile =  "/root/files/result/"+file
NewRoot = "files/result/"
zf.write(tofile, arcname=tofile.split(NewRoot)[1])

更多信息:

ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None) https://docs.python.org/3/library/zipfile.html


注:该函数用于Python的ZipFile库,用于将文件写入ZIP归档文件。

0

这是我使用的一个示例。我有一个名为Treport的Excel文件,在我的dowork函数中使用Python + Pandas创建透视表等,用于每个公司在CompanyNames中。我创建了CSV的zip文件和非zip文件,以便进行检查。 作者指定了我想要的.xlsx文件的路径,对于我的zip文件,我在zip.write()中指定。我只指定最近创建的xlsx文件的名称,这就是被压缩的内容,而不是整个目录。之前我只是指定“writer”,并将整个目录压缩。这使我能够仅压缩最近创建的Excel文件。

Treport = 'TestReportData.csv'
CompanyNames = ['Company1','Company2','Company3']
for CompName in CompanyNames:
    strcomp = str(CompName)
    #Writer Creates pathway to output report to. Each company gets unique file.
    writer = pd.ExcelWriter(f"C:\\Users\\MyUser\\Documents\\{strcomp}addReview.xlsx", engine='xlsxwriter')
    DoWorkFunction(CompName, Treport, writer)
    writer.save()
    with ZipFile(f"C:\\Users\\MyUser\\Documents\\{strcomp}addR.zip", 'w') as zip:
        zip.write(writer, f"{strcomp}addReview.xlsx")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接