Pythonic检索区分大小写路径的方法?
我想知道是否有一种更快的方法来实现在python中返回区分大小写路径的函数。我提出的一个解决方案同时适用于linux和windows,但需要迭代os.listdir,这可能会很慢 此解决方案适用于不需要大量速度的应用程序和上下文:Pythonic检索区分大小写路径的方法?,python,linux,windows,path,directory,Python,Linux,Windows,Path,Directory,我想知道是否有一种更快的方法来实现在python中返回区分大小写路径的函数。我提出的一个解决方案同时适用于linux和windows,但需要迭代os.listdir,这可能会很慢 此解决方案适用于不需要大量速度的应用程序和上下文: def correctPath(start, path): 'Returns a unix-type case-sensitive path, works in windows and linux' start = unicode(start);
def correctPath(start, path):
'Returns a unix-type case-sensitive path, works in windows and linux'
start = unicode(start);
path = unicode(path);
b = '';
if path[-1] == '/':
path = path[:-1];
parts = path.split('\\');
d = start;
c = 0;
for p in parts:
listing = os.listdir(d);
_ = None;
for l in listing:
if p.lower() == l.lower():
if p != l:
c += 1;
d = os.path.join(d, l);
_ = os.path.join(b, l);
break;
if not _:
return None;
b = _;
return b, c; #(corrected path, number of corrections)
>>> correctPath('C:\\Windows', 'SYSTEM32\\CmD.EXe')
(u'System32\\cmd.exe', 2)
但是,当上下文从一个50000多个条目的大型数据库中收集文件名时,速度就不会那么快了
一种方法是为每个目录创建一个dict树。将dict树与路径的目录部分相匹配,如果出现密钥丢失,则执行os.listdir以查找并创建新目录的dict条目,并删除未使用的部分或保留变量计数器作为分配“生存期”的方法到每个目录。以下是您自己的代码的轻微重写,有三个修改:匹配前检查文件名是否已正确,测试前将列表处理为小写,使用索引查找相关的“true case”文件
def corrected_path(start, path):
'''Returns a unix-type case-sensitive path, works in windows and linux'''
start = unicode(start)
path = unicode(path)
corrected_path = ''
if path[-1] == '/':
path = path[:-1]
parts = path.split('\\')
cd = start
corrections_count = 0
for p in parts:
if not os.path.exists(os.path.join(cd,p)): # Check it's not correct already
listing = os.listdir(cd)
cip = p.lower()
cilisting = [l.lower() for l in listing]
if cip in cilisting:
l = listing[ cilisting.index(cip) ] # Get our real folder name
cd = os.path.join(cd, l)
corrected_path = os.path.join(corrected_path, l)
corrections_count += 1
else:
return False # Error, this path element isn't found
else:
cd = os.path.join(cd, p)
corrected_path = os.path.join(corrected_path, p)
return corrected_path, corrections_count
我不确定这是否会快得多,尽管正在进行的测试稍微少了一点,加上开始时的“已经正确”捕获可能会有所帮助。一个扩展版本,带有不区分大小写的缓存以拉出正确的路径:
import os,re
def corrected_paths(start, pathlist):
''' This wrapper function takes a list of paths to correct vs. to allow caching '''
start = unicode(start)
pathlist = [unicode(path[:-1]) if path[-1] == '/' else unicode(path) for path in pathlist ]
# Use a dict as a cache, storing oldpath > newpath for first-pass replacement
# with path keys from incorrect to corrected paths
cache = dict()
corrected_path_list = []
corrections_count = 0
path_split = re.compile('(/+|\+)')
for path in pathlist:
cd = start
corrected_path = ''
parts = path_split.split(path)
# Pre-process against the cache
for n,p in enumerate(parts):
# We pass *parts to send through the contents of the list as a series of strings
uncorrected_path= os.path.join( cd, *parts[0:len(parts)-n] ).lower() # Walk backwards
if uncorrected_path in cache:
# Move up the basepath to the latest matched position
cd = os.path.join(cd, cache[uncorrected_path])
parts = parts[len(parts)-n:] # Retrieve the unmatched segment
break; # First hit, we exit since we're going backwards
# Fallback to walking, from the base path cd point
for n,p in enumerate(parts):
if not os.path.exists(os.path.join(cd,p)): # Check it's not correct already
#if p not in os.listdir(cd): # Alternative: The above does not work on Mac Os, returns case-insensitive path test
listing = os.listdir(cd)
cip = p.lower()
cilisting = [l.lower() for l in listing]
if cip in cilisting:
l = listing[ cilisting.index(cip) ] # Get our real folder name
# Store the path correction in the cache for next iteration
cache[ os.path.join(cd,p).lower() ] = os.path.join(cd, l)
cd = os.path.join(cd, l)
corrections_count += 1
else:
print "Error %s not in folder %s" % (cip, cilisting)
return False # Error, this path element isn't found
else:
cd = os.path.join(cd, p)
corrected_path_list.append(cd)
return corrected_path_list, corrections_count
在为一组路径运行的示例中,这大大减少了ListDir的数量(这显然取决于路径的相似程度):
在此过程中,我意识到MacOSX上的Python返回路径匹配,就好像它们不区分大小写一样,因此存在性测试总是成功的。在这种情况下,可以将listdir向上移动以替换它。只是一个旁注,PEP8说您应该始终将docString括在三个双引号中,如下所示:
“返回unix类型的区分大小写的路径,在windows和linux中工作”“”
另一个注意事项是,在Python中,正向斜杠在路径(包括windows)中有效。因此,您可以始终在内部使用/
,只有在Python之外需要时才呈现````代码。对不起,另请注意。分号是怎么回事?除非将多个程序行放在一个文本行上,否则您并不真正需要它们,即使这样,这也被认为是不好的做法。我使用的数据库使用windows路径,因此我认为我不必太担心。我正在将一个元数据数据库从Winamp转换为Rhythymbox。也谢谢你的文档提示,没有人告诉我这些事情。关于分号的事,我也忍不住要说。如果我要发布我的程序,我保证我会删除它们。听起来像是一个有趣的项目。不确定一次先把它们全部放下来比每次检查一次把它们全部放下来要快,但它确实看起来更好。是的,尽管我认为即使是一个庞大的列表,也会相当快。如果您正在处理>1路径,则最大的加速将是通过缓存每个级别的更正。我会推出树的每个步骤(纠正的_路径,以及从p构建的等效未纠正的_路径),并在开始行走之前使用它执行查找。如果您愿意,我可以写一个例子?您的意思是将以前更正的路径存储在缓存中以最小化os.listdir调用?如果是这样的话,那么我已经把这个实现放在某个地方了,再发布一个也不会有什么坏处。看起来不错。我非常喜欢用于检测冗余斜杠的regex对象。我认为应该是r'(/++\+)”
,使用[]
会无意中匹配
字符。
corrected_paths('/Users/', ['mxF793/ScRiPtS/meTApaTH','mxF793/ScRiPtS/meTApaTH/metapAth/html','mxF793/ScRiPtS/meTApaTH/metapAth/html/css','mxF793/ScRiPts/PuBfig'])
([u'/Users/mxf793/Scripts/metapath', u'/Users/mxf793/Scripts/metapath/metapath/html', u'/Users/mxf793/Scripts/metapath/metapath/html/css', u'/Users/mxf793/Scripts/pubfig'], 14)
([u'/Users/mxf793/Scripts/metapath', u'/Users/mxf793/Scripts/metapath/metapath/html', u'/Users/mxf793/Scripts/metapath/metapath/html/css', u'/Users/mxf793/Scripts/pubfig'], 5)