首页 > 解决方案 > 通过Python中的目录循环成对组合?

问题描述


主要流程如下:

一个带有 B、C、D... 子文件夹的主文件夹 A。这个主文件夹有的正在考虑的文件。大多数子文件夹都有 shp。

但是还有另一个主文件夹。让我们用 L、M、N .. 子文件夹来称它为 K。这些子文件夹与另一个文件夹的其他子文件夹与文件相对应。

A中的子文件夹与K中的子文件夹具有相同的名称,尽管K可能有更多我们不需要的。

我希望用户插入主文件夹的A目录并从第一个子文件夹中读取第一个 shp(如果那里存在 shp)然后转到另一个old主文件夹并检查相应的子文件夹,shp从那里获取并进行一些比较在它们之间并打印结果(斜体部分我已经解决了它们),然后相应地继续处理new文件夹的其余子文件夹。如果在一个子文件夹中没有 shp,它应该打印:'文件夹名称'没有 shp。并继续其余的。

我该怎么做?

我已经尝试过这段代码,它的某些部分在哪里:它将每个子文件夹中的每个 shp 存储到一个列表中,但来自第一个主文件夹。它需要从两个主要文件夹中进行比较才能成功。

import fiona
from pprint import pprint
import os

rootdir = r'C:\Users\user\Desktop\a' # path to the root directory you walk
    sfiles = [] # a list with all the .shp files
    for entry in os.listdir(rootdir):
        dirpath = os.path.join(rootdir, entry)
        if os.path.isdir(dirpath): 
            for file in os.listdir(dirpath): # Get all files in the subdirectories
                if file.endswith('.shp'): # If it's an .shp.
                    filepath = os.path.join(dirpath, file)
                    sfiles.append(fiona.open(filepath))

我什么时候应该在每个 shapefiles.schema 片段之间添加这种组合?如果手动插入 shapefile,我会这样做:

pst_n=fiona.open(r'C:\Users\user\Desktop\new\PST')#new pst
pst_o=fiona.open(r'C:\Users\user\Desktop\old\PST')#old_pst
pst_n.schema
d1 = pst_n.schema['properties']
d2 = pst_o.schema['properties']

d1_items = set(d1.items())
d2_items = set(d2.items())
result = sorted([(k, 'd1', v) for k, v in d1_items if (k, v) not in d2_items] +
                [(k, 'd2', v) for k, v in d2_items if (k, v) not in d1_items])

result = [(k, v, d) for k, d, v in result]


pprint(result)

并显示这样的差异:

[('ADDRESS', 'int:4', 'd1'),
 ('ADDRESS', 'str:254', 'd2'),
 ('AREA', 'float:19.11', 'd2'),
 ('DEC_ID', 'int:4', 'd1'),
 ('DEC_ID', 'str:254', 'd2'),
 ('DESC_', 'str:254', 'd1'),
 ('FID_PERIVL', 'int:9', 'd1'),
 ('KAEK', 'str:50', 'd1'),
 ('KAEK', 'str:12', 'd2'),
 ('LEN', 'float:19.11', 'd2'),

现在我应该如何显示每个组合在循环时的差异?

可以测试它是否有效的文件在这里: http ://www.mediafire.com/file/644y8e12pj9jrei/main_folders.zip

标签: python

解决方案


您可以通过使用来进行收集大大简化您的文件收集代码os.walk();您可以使用fnmatch.filter()将文件名过滤为仅*.shp文件:

import os
import fnmatch

def new_file_paths(rootdir):
    for dirpath, dirnames, filenames in os.walk(rootdir):
        if dirpath == rootdir: continue. # ignore files in the root
        yield dirpath, [os.path.join(dirpath, fname) for fname in fnmatch.filter(filenames, '*.shp')]

这是一个生成器函数,可生成每个目录的文件列表,因此您可以打印每个目录的信息以提供给用户。'os.walk()` 将遍历所有子目录,在任何深度,从根开始。

如果这是一个问题,并且要忽略进一步的嵌套目录,那么glob.iglob()在目录名称上使用 with 分组会更简单:

from glob import iglob
from itertools import groupby

def new_file_paths(rootdir):
    # only .shp files in direct subfolders 
    results = igblob(os.path.join(rootdir, '*', '*.shp'))
    return ((d, list(p)) for d, p in groupby(results, key=os.path.dirname))

循环生成器对象时,可以获取目录中每个文件的相对路径名,并检查其他位置是否存在对应文件:

rootdir_new = r'C:\Users\user\Desktop\a'
rootdir_old = r'C:\Users\user\Desktop\k'

for directory, paths in new_file_paths(rootdir_new)):
    if not paths:
        print('{} is empty, no new files found'.format(directory))
        continue

    for path in paths:
        relative_path = os.path.relpath(path, rootdir_new)
        old_path = os.path.join(rootdir_old, relative_path)
        if not os.path.exists(old_path):
            # no corresponding old file
            print('No matching previous version of {}' 
                  'found, skipping'.format(relative_path))
            continue

        # compare `path` with `old_path`

至于您的比较代码,您可以利用dict.items() 字典视图对象是一个集合的事实,因此您可以直接对它们使用集合操作而无需调用set()它们,并且集合本身支持产生差异。并且sorted()可以带一个关键函数,这样你就可以对你的结果进行排序,而不必重新排列你的输出列表:

from operator import itemgetter

d1 = pst_n.schema['properties']
d2 = pst_o.schema['properties']

changed = {'d1': d1.items() - d2.items(), 'd2': d2.items() - d1.items()}
results = sorted(
    ((k, v, d) for d in changed for k, v in changed[d]),
    key=itemgetter(0, 2)) # sort by key, then source. Values will *always* differ.

推荐阅读