2012-01-13 23 views
5

İçindeki dosyaları kontrol etmem gereken bir yol listesi verdim. Tabii ki, bir root ve bir alt dizin verildiyse, alt dizini işlemeye gerek yoktur. Örneğin, bir yolun diğerinin bir alt dizini olmadığını (çapraz platform) nasıl anlayabilirim (çapraz platform). Tercihen bunun çapraz platform olmasını isterim ve döngüsel olmadıkça symlinks hakkında endişelenmem (daha da kötüsü, verileri iki kez işlediğimdir).Bir yolun başka bir alt dizini olup olmadığı nasıl belirlenir?

GÜNCELLEME: Burada ben kullanarak sona erdi kodu sayesinde ben zaten işledik dizinleri bir dizi koruyacağını ve ardından her yeni yol kontrolü herhangi olup olmadığını görmek üzere

def unique_path_roots(paths): 
    visited = set() 
    paths = list(set(paths)) 

    for path in sorted(paths,key=cmp_to_key(locale.strcoll)): 
     path = normcase(normpath(realpath(path))) 

     head, tail = os.path.split(path) 
     while head and tail: 
      if head in visited: 
       break 
      head, tail = os.path.split(head) 
     else: 
      yield path 
      visited.add(path) 

cevap

6

@FJ için üst dizinleri zaten işlemeden önce bu sette vardır: varsa alt dizinleri, üst dizinlere sonra hep olacak şekilde

import os.path 

visited = set() 
for path in path_list: 
    head, tail = os.path.split(path) 
    while head and tail: 
     if head in visited: 
      break 
     head, tail = os.path.split(head) 
    else: 
     process(path) 
     visited.add(path) 

Not path_list olduğu sıralanmalıdır.

+0

Bu bir liste tarayarak yerine üyelik testleri set çünkü benim öneri daha hızlı olacaktır. Bunu sevdim. – kindall

+0

@ F.J bir infitie döngü gibi gözüküyor, kafa c: \ 'ye çok dibinde indiriyor ve asla Hiçbiri olarak ayarlanmadı. – esac

+0

@esac - Bunun için üzgünüm, temel durumda herşeyi başa değil kuyruğa sokacağını düşünmüştüm. Sorunu çözmem gereken düzenlemeye bakın. –

2

Zaten işlediğiniz dizinleri (normalize edilmiş bir formda) izleyin ve daha önce görmüşseniz tekrar işlemeyin. Böyle bir şey çalışması gerekir:

from os.path import realpath, normcase, sep 

dirs = [r"C:\test", r"C:\test\pics", r"C:\test2"] 

processed = [] 

for dir in dirs: 
    dir = normcase(realpath(dir)) + sep 
    if not any(dir.startswith(p) for p in processed): 
     processed.append(dir) 
     process(dir)   # your code here 
+1

'commonprefix ([r'C: \ test2 ', r'C: \ test']) -> 'C: \\ test'' –

+0

Evet, iç çekiş. Bu gerçekten gerekeni yapmıyor, IMHO. Basit bir 'beginwith()' yapmak için onu değiştirdi - normalleştirilmiş olduğundan iyi olacak. – kindall

+0

Evet, gerçekten commonprefix'in davranışı biraz garip, sanki sadece dizin kırıklarını kontrol etmeli gibi görünüyor, çünkü os.path' modülünden geliyor, ah. –

8
def is_subdir(path, directory): 
    path = os.path.realpath(path) 
    directory = os.path.realpath(directory) 

    relative = os.path.relpath(path, directory) 

    if relative.startswith(os.pardir): 
     return False 
    else: 
     return True 
+1

os.sep bir hata kaynağıdır :) –

+0

'r: 'relpath', 'D: \ bar' ile ilişkili olarak C: \ foo 'bulmaya çalışırken ms-windows'larda başarısız olabilir. – ideasman42

-1

Sabit ve basitleştirilmiş jgoeders 'ın versiyonu:

İşte
def is_subdir(suspect_child, suspect_parent): 
    suspect_child = os.path.realpath(suspect_child) 
    suspect_parent = os.path.realpath(suspect_parent) 

    relative = os.path.relpath(suspect_child, start=suspect_parent) 

    return not relative.startswith(os.pardir) 
+0

Neden başka bir yinelenen cevap eklemek yerine yayını düzenlemekle kalmıyoruz? – jgoeders

+0

Üzgünüz, bir kez Mavi Ay'a SO gönderirim ve bu özelliği kaçırdım. –

+0

'realpath' - burada sembolik bağları ortadan kaldırmak sorunludur. (birçok durumda, ne istediğinizi değil), aşağıdaki linkler yol düzenini tamamen değiştirebilir. – ideasman42

0

Ben ile geldi bir is_subdir yarar fonksiyonudur. Uyumlu

  • Python3.x (ayrıca destekler os.path hem eşleşen bytes ve str ile çalışır).
  • Karşılaştırma yollarını normalleştirir.
    (ms-windows üzerinde çalışmak için ana hiyerarşi ve durum).
  • os.path.relpath kullanarak, yolları farklı sürücülerdeyse, MS pencerelerinde bir istisna oluşturacaktır. (C:\foo ->D:\bar)

Kodu:

def is_subdir(path, directory): 
    """ 
    Returns true if *path* in a subdirectory of *directory*. 
    """ 
    import os 
    from os.path import normpath, normcase, sep 
    path = normpath(normcase(path)) 
    directory = normpath(normcase(directory)) 
    if len(path) > len(directory): 
     sep = sep.encode('ascii') if isinstance(directory, bytes) else sep 
     if path.startswith(directory.rstrip(sep) + sep): 
      return True 
    return False 
İlgili konular