【问题标题】:How to list all directories that do not contain a file type?如何列出所有不包含文件类型的目录?
【发布时间】:2015-09-29 13:07:12
【问题描述】:

如果它们不包含某些文件类型,我将尝试返回所有目录的唯一列表 (set)。如果未找到该文件类型,则将该目录名称添加到列表中以供进一步审核。

下面的函数将查找所有有效文件夹并将其添加到集合中以进行进一步比较。我想将此扩展为仅返回那些不包含out_list 中的文件的目录。这些目录可能包含带有out_list 文件的子目录。如果这是真的,我只想要有效目录的文件夹名称的路径。

# directory = r'w:\workorder'
#
# Example:
# w:\workorder\region1\12345678\hi.pdf
# w:\workorder\region2\23456789\test\bye.pdf
# w:\workorder\region3\34567891\<empty>
# w:\workorder\region4\45678912\Final.doc
# 
# Results:
# ['34567891', '45678912']

job_folders = set([]) #set list is unique
out_list = [".pdf", ".ppt", ".txt"]

def get_filepaths(directory):
    """
    This function will generate the file names in a directory
    tree by walking the tree either top-down or bottom-up. For each
    directory in the tree rooted at directory top (including top itself),
    it yields a 3-tuple (dirpath, dirnames, filenames).
    """

    folder_paths = []  # List which will store all of the full filepaths.

    # Walk the tree.

    for item in os.listdir(directory):
        if os.path.isdir(os.path.join(directory, item)):
            folderpath = os.path.join(directory, item) # Join the two strings in order to form the full folderpath.
            if re.search('^[0-9]', item):
                job_folders.add(item[:8])
            folder_paths.append(folderpath)  # Add it to the list.
    return folder_paths

【问题讨论】:

    标签: python directory subdirectory os.walk


    【解决方案1】:

    获取文件扩展名:

    name,ext = os.path.splitext(os.path.join(directory,item))
    if ext not in out_list:
        job_folders.add(item[:8])
    

    【讨论】:

    • “您必须删除扩展列表中的句点或稍微更改代码” ==> 这是不正确os.path.splitext docs明确说明返回的扩展包含句点。
    【解决方案2】:

    这是你想要的吗?

    import os
    
    def main():
        exts = {'.pdf', '.ppt', '.txt'}
        for directory in get_directories_without_exts('W:\\workorder', exts):
            print(directory)
    
    def get_directories_without_exts(root, exts):
        for root, dirs, files in os.walk(root):
            for file in files:
                if os.path.splitext(file)[1] in exts:
                    break
            else:
                yield root
    
    if __name__ == '__main__':
        main()
    

    编辑:查看您的要求后,我决定创建一个树对象来分析您的目录结构。创建后,很容易通过缓存进行递归查询以查明目录是否“正常”。从那里开始,创建一个只查找“不正常”的顶级目录的生成器非常简单。可能有更好的方法来做到这一点,但代码至少应该可以工作。

    import os
    
    def main():
        exts = {'.pdf', '.ppt', '.txt'}
        for directory in Tree('W:\\workorder', exts).not_okay:
            print(directory)
    
    class Tree:
    
        def __init__(self, root, exts):
            if not os.path.isdir(root):
                raise ValueError('root must be a directory')
            self.name = root
            self.exts = exts
            self.files = set()
            self.directories = []
            try:
                names = os.listdir(root)
            except OSError:
                pass
            else:
                for child in names:
                    path = os.path.join(root, child)
                    if os.path.isfile(path):
                        self.files.add(os.path.splitext(child)[1])
                    elif os.path.isdir(path):
                        self.directories.append(self.__class__(path, exts))
            self._is_okay = None
    
        @property
        def is_okay(self):
            if self._is_okay is None:
                self._is_okay = any(c.is_okay for c in self.directories) or \
                                any(c in self.exts for c in self.files)
            return self._is_okay
    
        @property
        def not_okay(self):
            if self.is_okay:
                for child in self.directories:
                    for not_okay in child.not_okay:
                        yield not_okay
            else:
                yield self.name
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

    • os.walk 的简洁插图。与my solution 一样,这里的问题是@user3594678 对于“包含”文件是否是递归的并不明确。看起来你假设是非递归的,就像我一样。
    • @user3594678 新代码效果更好吗?这有点复杂,但应该按照要求做(如果我正确理解了您的问题)。
    • @DanLenski 第二个示例被设计为在Tree 对象的所有三个方法中递归。目前还不完全清楚这是否可以变得更简单。您必须找到脏树的“根”,如果问题被正确理解,则返回它们。
    • 这对我来说是错误的。我在 Python 2.7.8 上。 File "&lt;module3&gt;", line 55 yield from c.not_okay ^ SyntaxError: invalid syntax 我删除了 from 然后得到这个: ` File "", line 39, in init self.directories.append(type(self)(path, exts)) TypeError : 必须是 classobj,而不是 str`
    • @user3594678 很抱歉!该代码是用 Python 3.4.3 编写的,但现在已更正。代码应该可以在 Python 2.7.8 中运行,因为已经进行了更改。
    【解决方案3】:

    您是否从其他地方复制并粘贴了现有代码?因为文档字符串似乎是 os.walk...

    您的问题有几点不清楚:

    1. 您声明代码的目标是“返回所有目录的唯一列表(集),如果它们不包含某些文件类型”。
      • 首先listset是不同的数据结构。
      • 其次,您的代码创建每个job_folders 是包含数字的文件夹名称的set,而folder_paths 是文件夹的完整路径list,无论是否它们是否包含数字。
      • 实际上想要在这里输出什么?
    2. 是否应该递归定义“那些不包含 out_list 中的文件的目录”,还是只包含这些目录的第一级内容? 我的解决方案假设是后者
      • 您的示例在这一点上是矛盾的:它在结果中显示34567891,但在结果中没有 region3。无论定义是否递归,region3 都应该包含在结果中,因为region3 不包含任何具有列出的扩展名的文件。
    3. job_folders 应该只填充满足其内容标准的目录,还是填充包含数字的所有文件夹名称? 我的解决方案假设是后者

    我要强调的一个poor practice in your code 是您对全局变量out_listjob_folders 的使用。 我已将前者更改为get_filepaths 的第二个参数,将后者更改为第二个返回值。

    不管怎样,解决办法就到这里了……

    import os, re
    
    ext_list = [".pdf", ".ppt", ".txt"]
    
    def get_filepaths(directory, ext_list):
        folder_paths = []  # List which will store all of the full filepaths.
        job_folders = set([])
    
        # Walk the tree.
    
        for dir, subdirs, files in os.walk(directory):
            _, lastlevel = os.path.split(dir)
            if re.search('^[0-9]', lastlevel):
                job_folders.add(lastlevel[:8])
    
            for item in files:
                root, ext = os.path.splitext(item)
                if ext in ext_list:
                    break
            else:
                # Since none of the file extensions matched ext_list, add it to the list of folder_paths
                folder_paths.append(os.path.relpath(dir, directory))
    
        return folder_paths, job_folders
    

    我在/tmp 下创建了一个与您相同的目录结构并运行以下命令:

    folder_paths, job_folders = get_filepaths( os.path.expandvars(r"%TEMP%\workorder"), ext_list )
    
    print "folder_paths =", folder_paths
    print "job_folders =", job_folders
    

    这是输出:

    folder_paths = ['.', 'region1', 'region2', 'region2\\23456789', 'region3', 'region3\\34567891', 'region4', 'region4\\456789123']
    job_folders = set(['12345678', '23456789', '34567891', '45678912'])
    

    如您所见,region1\12345678region2\23456789\test包含在输出 folder_paths 中,因为它们确实 直接包含指定扩展名的文件;所有其他子目录包含在输出中,因为它们直接包含指定扩展名的文件。

    【讨论】:

    • 好吧...?那是什么意思?他的解决方案是你想要的吗? (而且你应该投票赞成对你有用的答案,不仅仅是我的,而是所有有用的。)
    • 谢谢!使用@Noctis Skytower 示例得到以下结果: \\server\WorkOrder\Region1\07859436\Test \\server\WorkOrder\Region1\07859436\Clerical \\server\WorkOrder\Region1\07859436\GFW \\server\WorkOrder\Region1\ 07859475 \\server\WorkOrder\Region1\07859475\CLERICAL \\server\WorkOrder\Region1\07859475\GFW 如果在任何子目录中都找不到 ext_list 中的文件,我真正想要的是一个唯一的文件夹名称列表。 ex ['07859436', '07859475'] 抱歉不清楚...我一直在尝试各种不同的事情。
    • ...我是新来的,不擅长格式化帖子:(
    • “如果在任何子目录中都找不到 ext_list 中的文件,我真正想要的是一个唯一的文件夹名称列表” ==> 为什么CLERICAL 不应该 在输出中,因为CLERICAL also 不包含任何具有给定ext_list 的文件?包含07859475 但不包含CLERICAL 的规则是什么?
    • 07859475 是我的 8 位密钥,也就是 JobID。它是我在相应数据库中的主键。我需要确保用户将 PDF 存储在该 JobID 文件夹 的某个位置......无论它是在名为 CLERICALTEMP 的子目录中都没有关系。我只关心它的存在。我的目标是在数据库中找到没有 PDF 并标记为“完成”的作业。
    【解决方案4】:

    感谢@DanLenski 和@NoctisSkytower,我能够解决这个问题。 我的WorkOrder 目录在走in_path 时始终是第7 个文件夹,我发现使用os.sep
    我借鉴了您的两个解决方案并提出了以下建议:

    import os, re
    
    ext_list = [".pdf"]
    in_path = r'\\server\E\Data\WorkOrder'
    
    def get_filepaths(directory, ext_list):
        not_okay = set([])  # Set which will store Job folder where no ext_list files found
        okay = set([]) # Set which will store Job folder where ext_list files found
        job_folders = set([]) #valid Job ID folder
    
        # Walk the tree.
        for dir, subdirs, files in os.walk(directory):
    
            for item in files:
                root, ext = os.path.splitext(item)
    
                if len(dir.split(os.sep)) >= 8: #Tree must contain Job ID folder
                    job_folder = dir.split(os.sep)[7]
                    if ext in ext_list:
                        okay.add(job_folder)
                    else: # Since none of the file extensions matched ext_list, add it to the list of folder_paths
                        not_okay.add(job_folder)
    
        bad_list = list(not_okay - okay)
        bad_list.sort()
    
        return bad_list
    
    bad_list = get_filepaths( os.path.expandvars(in_path), ext_list )
    

    【讨论】:

      猜你喜欢
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-30
      • 2021-01-05
      • 1970-01-01
      相关资源
      最近更新 更多