从 zip 文件中提取文件并保留 mod 日期?

Posted

技术标签:

【中文标题】从 zip 文件中提取文件并保留 mod 日期?【英文标题】:Extract files from zip file and retain mod date? 【发布时间】:2012-03-21 21:36:45 【问题描述】:

我正在尝试使用 Python 2.7.1(在 Windows 上,仅供参考)从 zip 文件中提取文件,并且我的每次尝试都显示提取的文件,其中修改日期 = 提取时间(这是不正确的)。

import os,zipfile
outDirectory = 'C:\\_TEMP\\'
inFile = 'test.zip'
fh = open(os.path.join(outDirectory,inFile),'rb') 
z = zipfile.ZipFile(fh)
for name in z.namelist():
    z.extract(name,outDirectory)
fh.close()

我也尝试使用 .extractall 方法,结果相同。

import os,zipfile
outDirectory = 'C:\\_TEMP\\'
inFile = 'test.zip'
zFile = zipfile.ZipFile(os.path.join(outDirectory,inFile))        
zFile.extractall(outDirectory)

谁能告诉我我做错了什么?

我想这是可能的,而无需根据How do I change the file creation date of a Windows file? 对修改后的时间进行后期更正。

【问题讨论】:

你会很失望的...... 即使对于 Python 3.X,这似乎仍然是一个问题。 【参考方案1】:

嗯,确实需要一些后期处理,但还不错:

import os
import zipfile
import time

outDirectory = 'C:\\TEMP\\'
inFile = 'test.zip'
fh = open(os.path.join(outDirectory,inFile),'rb') 
z = zipfile.ZipFile(fh)

for f in z.infolist():
    name, date_time = f.filename, f.date_time
    name = os.path.join(outDirectory, name)
    with open(name, 'wb') as outFile:
        outFile.write(z.open(f).read())
    date_time = time.mktime(date_time + (0, 0, -1))
    os.utime(name, (date_time, date_time))

好吧,也许它那么糟糕。

【讨论】:

这行得通,谢谢。只是为了澄清一下,在提取文件时维护 mod 日期是 Python 的 zipfile 实现的限制,还是所有 zip 库的标准功能? 回复已经5年了,在Python 3.6下依然可以正常工作。它仍然像你写它的那一天一样丑陋,但它有效。 Python 3.6 还需要这个吗?查看源代码,我没有看到与日期/时间信息相关的任何更改... 您能解释一下为什么将 (0, 0, -1) 添加到 date_time 中吗?当前是第二次关闭吗? @RvdK:添加了(0, 0, -1),因为time.mktime 需要一个9 元素tuple-1 表示 DST 标志未知。【参考方案2】:

根据 Ethan Fuman 的回答,我开发了这个更简洁的版本(使用 Python 2.6.6):

zf = ZipFile('archive.zip', 'r')
for zi in zf.infolist():
    zf.extract(zi)
    date_time = time.mktime(zi.date_time + (0, 0, -1))
    os.utime(zi.filename, (date_time, date_time))
zf.close()

这会提取到当前工作目录并使用 ZipFile.extract() 方法写入数据,而不是创建文件本身。

【讨论】:

我正在尝试使用此代码,但所有文件都保存到我的根目录中。我将在哪里定义我希望保存文件的路径? @newwebdev22 代码解压到当前目录。您可以更改它或将路径参数添加到 extract() 方法,如文档中的状态:docs.python.org/2/library/zipfile.html#zipfile.ZipFile.extract 此外,您可能不会检查 ZIP 存档的绝对路径。【参考方案3】:

根据 Jia103 的回答,我开发了一个函数(使用 Python 2.7.14),在提取所有内容后保留目录和文件日期。这可以隔离函数中的任何丑陋之处,您还可以使用 zipfile.Zipfile.extractAll() 或任何您想要的 zip 提取方法:

import time
import zipfile
import os

# Restores the timestamps of zipfile contents.
def RestoreTimestampsOfZipContents(zipname, extract_dir):
    for f in zipfile.ZipFile(zipname, 'r').infolist():
        # path to this extracted f-item
        fullpath = os.path.join(extract_dir, f.filename)
        # still need to adjust the dt o/w item will have the current dt
        date_time = time.mktime(f.date_time + (0, 0, -1))
        # update dt
        os.utime(fullpath, (date_time, date_time))

要保留日期,只需在提取完成后调用此函数。

这是一个示例,来自我编写的压缩/解压缩游戏保存目录的脚本:

        z = zipfile.ZipFile(zipname, 'r')
        print 'I have opened zipfile %s, ready to extract into %s' \
                % (zipname, gamedir)
        try: os.makedirs(gamedir)
        except: pass    # Most of the time dir already exists
        z.extractall(gamedir)
        RestoreTimestampsOfZipContents(zipname, gamedir)  #<--  USED
        print '%s zip extract done' % GameName[game]

感谢大家之前的回答!

【讨论】:

【参考方案4】:

根据 Ber 的回答,我开发了这个版本(使用 Python 2.7.11),它还考虑了目录 mod 日期。

from os import path, utime
from sys import exit
from time import mktime
from zipfile import ZipFile

def unzip(zipfile, outDirectory):
    dirs = 

    with ZipFile(zipfile, 'r') as z:
        for f in z.infolist():
            name, date_time = f.filename, f.date_time
            name = path.join(outDirectory, name)
            z.extract(f, outDirectory)

            # still need to adjust the dt o/w item will have the current dt
            date_time = mktime(f.date_time + (0, 0, -1))

            if (path.isdir(name)):
                # changes to dir dt will have no effect right now since files are
                # being created inside of it; hold the dt and apply it later
                dirs[name] = date_time
            else:
                utime(name, (date_time, date_time))

    # done creating files, now update dir dt
    for name in dirs:
       date_time = dirs[name]
       utime(name, (date_time, date_time))

if __name__ == "__main__":

    unzip('archive.zip', 'out')

    exit(0)

由于在其中创建提取文件时正在修改目录,因此在提取完成之前将其日期设置为os.utime 似乎没有意义,因此此版本缓存目录名称及其时间戳,直到到最后。

【讨论】:

以上是关于从 zip 文件中提取文件并保留 mod 日期?的主要内容,如果未能解决你的问题,请参考以下文章

将zip内容提取到与zip文件同名的目录中,保留目录结构[关闭]

如何在不使用 python 保留目录的情况下提取文件夹中的所有 .zip 扩展名?

从给定日期提取日、月和年的最快方法是啥?

如何从 zip 中提取 csv 文件并在 python 中将其保存到磁盘? [复制]

从 zip 文件中提取子文件

怎么从zip里提取文件 Python