【问题标题】:How to iterate through folder and get certain files from the subfolders grouped?如何遍历文件夹并从分组的子文件夹中获取某些文件?
【发布时间】:2021-11-17 12:57:54
【问题描述】:

我有一个文件夹,其中包含多个子文件夹,每个子文件夹包含我需要的 3-4 个文件。 我正在尝试遍历该文件夹并将每个子文件夹中的所有文件放入字典中,该字典稍后转储到 json 文件中。

到目前为止,我已经设法为单个文件执行此操作,json 文件如下所示:

这是代码:

import os
import json
myDir = "\\\iads011n\\ContinuousTesting\\DailyTesting\\REPORTS"
filelist = []
for path, subdirs, files in os.walk(myDir):
    for file in files:
        if (file.endswith('.xlsx') or file.endswith('.xls') or file.endswith('.XLS')) and "Release" in file and "Integrated" not in file:
            filelist.append(os.path.join(file))

myDict = dict(zip(range(len(filelist)), filelist))

result=[]
for k,v in myDict.items():
    result.append({'id' : k, 'name' : v})

with open('XLList.json', 'w') as json_file:
    json.dump(result, json_file)

但我想要实现的是:

这是文件夹:

其中一个子文件夹的内容如下所示:

所以基本上我需要的是分组同一子文件夹下的所有 xls/ xlsx 文件。 主要问题是并非所有子文件夹都包含相同的项目,有些可能只有一个 xlsx 文件,另一些可能只有 3 或 4 个,等等。

【问题讨论】:

  • 所以每个子文件夹会有不同的ID?您也可以布局您的目录的示例文件树吗?
  • 同样在您的情况下,您正在检查"Integrated" not in file,但在您的预期输出中,它们已包含:D 此外,"version" 文件不在条件下,但在预期输出中。由于细节不清楚,我投票结束这个问题。
  • 是的,所以每个子文件夹都有不同的 ID。而且,示例代码仅适用于一个文件,我必须匹配该文件,这就是为什么“集成”不在文件中。版本相同。
  • 但我想要的是有一个字典/列表或任何数据类型的对象,每个对象都应该有一个 id 和每个子文件夹中 xlsx 文件的名称。

标签: python dictionary xlsx subdirectory os.walk


【解决方案1】:

问题是,您没有“存储”每个文件所属的文件夹。解决方案如下:

result = []
for i, (path, subdirs, files) in enumerate(os.walk(myDir)): #use enumerate to track folder id
    subdir = {"id": i}
    j = 0 #file counter in subfolder
    for file in files:
        if (file.endswith('.xlsx') or file.endswith('.xls') or file.endswith('.XLS')) and "Release" in file and "Integrated" not in file:
            subdir[f"name{j}"] = file
            j += 1
    result.append(subdir)

编辑

忽略没有有用文件的文件夹:

result = []
i = 0 #track folder id manually
for path, subdirs, files in os.walk(myDir): 
    subdir = {}
    j = 0 #file counter in subfolder
    for file in files:
        if (file.endswith('.xlsx') or file.endswith('.xls') or file.endswith('.XLS')) and "Release" in file and "Integrated" not in file:
            subdir[f"name{j}"] = file
            j += 1
    if len(subdir) > 0:
        subdir = {"id": i}
        result.append(subdir)
        i += 1 #increase counter

【讨论】:

  • 谢谢你!这正是我一直在寻找的。但一个问题是,现在我的 id 数量增加了 3 倍,因为子文件夹可能包含我不关心的其他文件夹。知道我应该如何转移到另一个列表,其中只有具有 id 和名称的对象?一个例子:ibb.co/3r4nSM5
  • 您必须检查是否有任何文件满足最后一个 if 条件。我编辑了答案
【解决方案2】:

更新了将子文件夹的文件分离为单独对象的解决方案:

...  # other code before it

import re
results = []
for path, subdirs, files in os.walk(myDir):
    id = your_algo_to_get_id() 
    data = {'id': id}
    for i, file in enumerate(files):
        if re.search(r"[\s\S]*release[\s\S]*\.xlsx?$", file, re.I) and
        "integrated" not in file.lower(): 
            data[f'name{i}'] = file
    results.append(data)  # output : [ { 'id': 0, 'name1': '...', ...}, {'id': 1, 'name1': '...'}, ..]
            

旧解决方案

假设id = 0

result = {'id': 0}
for i, filename in enumerate(filelist):
    result[f'name{i}'] = filename

result 的 json 输出将是:

{
  "id": 0,
  "name0": "some-filename.xlsx",
  "name1": "some-filename.xlsx",
  "name2": "some-filename.xlsx",
  "name3": "some-filename.xlsx",
  ...
}

enumerate是python的内置函数。如果不想放name0,也可以从1开始。

result = {'id': 0}
for i, filename in enumerate(filelist, 1):
    ...

对您的代码的建议:

for path, subdirs, files in os.walk(myDir):
    for file in files:
        if (file.endswith('.xlsx') or file.endswith('.xls') or file.endswith('.XLS')) and "Release" in file and "Integrated" not in file:
            filelist.append(os.path.join(file))

我建议使用带有 ignorecase 的正则表达式 r"xlsx?$" 来匹配文件名,因此一个条件是处理所有场景:

test_filenames = ["sample-name.XLSX", "sample-name.xlsx","sample-name.xls", "sample-name.XLS"]
for filename in test_filenames:
    if re.search(r"xlsx?$", filename, re.I):
        # it's matching

【讨论】:

  • 我认为我没有让自己足够清楚。对此感到抱歉。但我想要实现的是每个 json 对象都应该包含一个 id 和子文件夹中文件的名称。所以基本上每个 json 对象都是一个子文件夹,其中包含 id(由我给出)和 xls 文件的名称。这是一个对象的示例:i.stack.imgur.com/4OMI4.png
  • 查看更新后的解决方案,希望稍作修改即可使用。
  • 它运行良好,但我遇到了与 @nckstr15 的解决方案相同的问题。我得到每个子文件夹的 id。有什么办法可以摆脱空ID?就像循环浏览文件夹以仅在第一个子文件夹中搜索时一样?像第一个孩子。
  • ibb.co/3r4nSM5 这是一个例子
  • 您的意思是忽略给定条件内没有任何文件的子文件夹?如果是,那么您可以在循环开始时忽略它: ``` id = 1 for path, subdirs, files in os.walk(myDir): data = {} for i, file in enumerate(files): if re .search(r"[\s\S]*release[\s\S]*\.xlsx?$", file, re.I) and "integrated" not in file.lower(): data[f'name {i}'] = file if not len(data): continue # 跳过它 id += 1 data['id'] = id results.append(data) ``