如何在Python中检查归档文件是文件还是文件夹?

9
我有一个归档文件,不想解压它,但要检查每个内容是文件还是目录。
os.path.isdir和os.path.isfile无法工作,因为我正在处理归档文件。该存档可以是tar、bz2、zip或tar.gz之一(因此我不能使用它们的特定库)。此外,代码应在任何平台上工作,如Linux或Windows。有人能帮我怎么做吗?

不行,因为存档可以是任何类型的(有很多种类型的存档)。 - Sam
2
理论上通过解析文件应该是可以做到的,但为什么你无法提取它们呢? - timgeb
也许其中一个可以帮助你入门: - timgeb
当然,您可以检查文件类型,然后使用相应的库。 - timgeb
1
有很多种类型的档案,不可能为每个类型编写单独的代码。尝试应用策略模式。大部分代码将被共享,只需对不同的库调用进行最小更改。 - timgeb
显示剩余5条评论
4个回答

17

你已经说明你需要支持 "tar, bz2, zip 或 tar.gz"。Python的 tarfile 模块会自动处理gz和bz2压缩的tar文件,因此实际上只需要支持两种压缩格式:tar 和 zip。(bz2本身不是一种压缩格式,它只是一种压缩方式)。

你可以使用 tarfile.is_tarfile() 来确定给定的文件是否为tar文件。这也适用于使用gzip或bzip2压缩的tar文件。在tar文件内,你可以使用 TarInfo.isdir() 来判断一个文件是否是目录,使用 TarInfo.isfile()来判断一个文件是否是普通文件。

同样地,你可以使用 zipfile.is_zipfile() 来确定一个文件是否是zip文件。在 zipfile 中没有区分目录和普通文件的方法,但是以 / 结尾的文件名是目录。

因此,给定一个文件名,你可以这样做:

import zipfile
import tarfile

filename = 'test.tgz'

if tarfile.is_tarfile(filename):
    f = tarfile.open(filename)
    for info in f:
        if info.isdir():
            file_type = 'directory'
        elif info.isfile():
            file_type = 'file'
        else:
            file_type = 'unknown'
        print('{} is a {}'.format(info.name, file_type))

elif zipfile.is_zipfile(filename):
    f = zipfile.ZipFile(filename)
    for name in f.namelist():
         print('{} is a {}'.format(name, 'directory' if name.endswith('/') else 'file'))

else:
    print('{} is not an accepted archive file'.format(filename))
当使用具有以下结构的tar文件运行时:
(py2)[mhawke@localhost tmp]$ tar tvfz /tmp/test.tgz drwxrwxr-x mhawke/mhawke 0 2016-02-29 12:38 x/ lrwxrwxrwx mhawke/mhawke 0 2016-02-29 12:38 x/4 -> 3 drwxrwxr-x mhawke/mhawke 0 2016-02-28 21:14 x/3/ drwxrwxr-x mhawke/mhawke 0 2016-02-28 21:14 x/3/4/ -rw-rw-r-- mhawke/mhawke 0 2016-02-28 21:14 x/3/4/zzz drwxrwxr-x mhawke/mhawke 0 2016-02-28 21:13 x/2/ -rw-rw-r-- mhawke/mhawke 0 2016-02-28 21:13 x/2/aa drwxrwxr-x mhawke/mhawke 0 2016-02-28 21:13 x/1/ -rw-rw-r-- mhawke/mhawke 0 2016-02-28 21:13 x/1/abc -rw-rw-r-- mhawke/mhawke 0 2016-02-28 21:13 x/1/ab -rw-rw-r-- mhawke/mhawke 0 2016-02-28 21:13 x/1/a
输出如下:
x是目录 x/4为未知类型 x/3是目录 x/3/4是目录 x/3/4/zzz是文件 x/2是目录 x/2/aa是文件 x/1是目录 x/1/abc是文件 x/1/ab是文件 x/1/a是文件
注意,x/4是“未知”的,因为它是符号链接。
使用zipfile没有简单的方法来区分符号链接(或其他文件类型)与目录或普通文件。这些信息可以在ZipInfo.external_attr属性中找到,但是要将其取回很麻烦:
import stat

linked_file = f.filelist[1]
is_symlink = stat.S_ISLNK(linked_file.external_attr >> 16L)

0
你可以使用 string.endswith(string) 方法来检查字符串是否具有正确的文件名扩展名:
filenames = ['code.tar.gz', 'code2.bz2', 'code3.zip']
fileexts = ['.tar.gz', '.bz2', '.zip']

def check_extension():
    for name in filenames:
        for ext in fileexts:
            if name.endswith(ext):
                print ('The file: ', name, ' has the extension: ', ext)


check_extension()

输出结果为:

The file:  code.tar.gz  has the extension:  .tar.gz
The file:  code2.bz2  has the extension:  .bz2
The file:  code3.zip  has the extension:  .zip

你需要为每个归档文件类型创建一个文件扩展名列表,以便进行检查,并需要将文件名加载到列表中,以便轻松执行检查,但我认为这将是解决你的问题的相当有效的方法。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Sam
抱歉,我犯了错误,我对你的问题的理解是错误的。 - Sean Pianka

0
你可以使用python-magic模块并解析它的输出。
[root@jasonralph ~]# yum install python-pip

[root@jasonralph ~]# pip install python-magic

[root@jasonralph ~]# cat py_file_check.py
#!/usr/bin/python

import magic
print magic.from_file('jason_ralph_org_20160215.tar.gz')

[root@jasonralph ~]# file jason_ralph_org_20160215.tar.gz
jason_ralph_org_20160215.tar.gz: gzip compressed data, from Unix, last   modified: Mon Feb 29 01:33:25 2016
> [root@jasonralph ~]# python py_file_check.py
>         gzip compressed data, from Unix, last modified: Mon Feb 29 01:33:25 2016

我正在检查存档内容的文件类型,而不是存档本身的类型。请阅读我的解决方案。它有效。 - Sam

0

我得到了答案。我们可以使用两个命令:archive.getall_members()和archive.getfile_members()。

我们遍历每一个成员并将文件/文件夹名称存储在两个数组a1(包含文件/文件夹名称)和a2(仅包含文件名)中。如果这两个数组都包含该元素,则它是一个文件,否则它是一个文件夹。


archive.getall_members()是什么?这是哪个软件包? - mhawke
它是utils.archives。 - Sam
“utils”包是什么?来自哪里?Django? - mhawke
是的,它来自Django。 - Sam
我在任何版本的Django中都找不到这两个函数。你使用的是哪个版本?你还应该知道,这些函数以及其他来自django.utils的函数可能会在未来的Django版本中消失。 - mhawke

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