python - 通过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
解决方案
您可以通过使用来进行收集大大简化您的文件收集代码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.
推荐阅读
- php - Composer 无法在 Windows (WSL) 上运行
- angular - Angular 6 Service 从方法内部添加新实例
- angularjs - AngularJS ng-model 奇怪的行为
- python - How do I queue QProcesses in PyQt5?
- android - 是否可以将 H.264 软件编解码器安装到 Google 的原生 Android WebRTC 库?
- .net - .NET 执行引擎与 BCL(基类库)合作
- c# - 如何正确使用 TestContext.Properties
- r - R groupby函数计算时间差
- angular - WebSocketSubject 不工作
- google-app-maker - 如何查询未设置的关系