os.Aşağıdaki dizinlere girmeden yürüyün


105

os.walkYalnızca sağladığım dizindeki dosyaları döndürmeyi nasıl sınırlayabilirim ?

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
    return outputList

2
Çok sayıda olası yaklaşımın ve bunlarla birlikte gelen tüm uyarıların olduğu başka bir durum, bu işlevselliğin Python standart kitaplığına eklenmesi gerektiğini göstermektedir.
2016

files_with_full_path = [f.path for f in os.scandir(dir) if f.is_file()]. Bunun f.nameyerine yalnızca dosya adlarını kullanmanız gerekirse f.path. Bu en hızlı çözümdür ve herhangi birinden çok daha hızlıdır walkveya listdirbkz. Stackoverflow.com/a/40347279/2441026 .
user136036

Yanıtlar:


105

walklevelİşlevi kullanın .

import os

def walklevel(some_dir, level=1):
    some_dir = some_dir.rstrip(os.path.sep)
    assert os.path.isdir(some_dir)
    num_sep = some_dir.count(os.path.sep)
    for root, dirs, files in os.walk(some_dir):
        yield root, dirs, files
        num_sep_this = root.count(os.path.sep)
        if num_sep + level <= num_sep_this:
            del dirs[:]

Aynı şekilde çalışır os.walk, ancak ona levelözyinelemenin ne kadar derine gideceğini gösteren bir parametre iletebilirsiniz .


3
Bu işlev aslında tüm yapı boyunca "dolaşıp" belirli bir noktanın altındaki girişleri siliyor mu? Yoksa daha akıllıca bir şey mi oluyor? Bunu kodla nasıl kontrol edeceğimi bile bilmiyorum. --python beginner
mathtick

1
@mathtick: İstenilen seviyede veya altında bir dizin bulunduğunda, tüm alt dizinleri daha sonra aramak için alt dizinler listesinden kaldırılır. Böylece "yürünmeyecekler".
nosklo

2
Dizinleri nasıl "sileceğim" konusunda zorlandığım için bunu + 1'ledim. Ben denemiş dirs = []ve dirs = Noneancak bu işe yaramadı. map(dirs.remove, dirs)çalıştı, ancak bazı istenmeyen '[Hiçbiri]' mesajları yazdırıldı. Öyleyse, neden del dirs[:]özellikle?
Zach Young

4
topdown=FalseOs.walk'ta kullanıldığında bunun çalışmadığını unutmayın. Belgelerdeki 4. paragrafa bakın :Modifying dirnames when topdown is False has no effect on the behavior of the walk, because in bottom-up mode the directories in dirnames are generated before dirpath itself is generated.
dthor

3
@ZacharyYoung dirs = []ve dirs = Noneişe yaramayacak çünkü sadece yeni bir ilgisiz nesne yaratıyorlar ve isme atıyorlar dirs. Orijinal liste nesnesinin adının değil yerinde değiştirilmesi gerekir dirs.
nosklo

207

Os.walk'u kullanmayın.

Misal:

import os

root = "C:\\"
for item in os.listdir(root):
    if os.path.isfile(os.path.join(root, item)):
        print item

1
@ 576i: bu, dosyalar ve dizinler arasında ayrım yapmaz

4
@Alexandr os.path.isfileve os.path.isdirfarklılaşmanızı sağlar. Çünkü ben, alamadım os.path.isfile'08 beri örnek kodda olduğu ve yorumunuz '16 değil. Bir dizinde gezinmek değil, onu listelemek niyetinde olduğunuz için, bu açıkça daha iyi cevaptır.
Daniel F

@DanielF, burada kastettiğim, tüm öğeler üzerinde döngü oluşturmanız gerektiğidir ve walksize hemen ayrı dizin ve dosya listelerini verir.

Ah tamam. Aslında Alex'in cevabı daha iyi görünüyor (kullanıyor .next()) ve fikrinize çok daha yakın.
Daniel F

Python 3.5, os.scandirdaha karmaşık dosya-veya dizin-nesne etkileşimine izin veren bir işleve sahiptir. Aşağıdaki cevabımı görün
ascripter

48

Çözümün aslında çok basit olduğunu düşünüyorum.

kullanım

break

for döngüsünün yalnızca ilk yinelemesini yapmak için daha zarif bir yol olmalıdır.

for root, dirs, files in os.walk(dir_name):
    for f in files:
        ...
        ...
    break
...

Os.walk'u ilk kez çağırdığınızda, geçerli dizin için laleler döndürür, ardından bir sonraki döngüde sonraki dizinin içeriğini döndürür.

Orijinal senaryoyu alın ve bir ara ekleyin .

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
        break
    return outputList

9
Bu kabul edilen cevap olmalıydı. Basitçe "for f in files" döngüsünden sonra "break" eklemek özyinelemeyi durdurur. Ayrıca yukarıdan aşağıya = Doğru olduğundan emin olmak isteyebilirsiniz.
Alecz

23

Kullanmak için öneri listdiriyi bir öneridir . Python 2'de sorunuzun doğrudan cevabı şudur:root, dirs, files = os.walk(dir_name).next() .

Eşdeğer Python 3 sözdizimi root, dirs, files = next(os.walk(dir_name))


1
Oh, ondan bir tür komik hata alıyordum. ValueError: paketten
çıkarmak

1
Güzel! Yine de bir hack gibi geliyor. Bir motoru çalıştırıp sadece bir devir yapmasına izin verdiğinizde ve ardından ölmesine izin vermek için anahtarı çektiğinizde olduğu gibi.
Daniel F

Bunun karşısında tökezledi; root, dirs, files = os.walk(dir_name).next()verir banaAttributeError: 'generator' object has no attribute 'next'
Evan

3
@Evan, muhtemelen bunun nedeni 2008'den kalma ve Python 2 sözdizimini kullanıyor. Python 3'te yazabilirsiniz root, dirs, files = next(os.walk(dir_name))ve ardından değişkenler root, dirs, filesyalnızca seviyedeki oluşturucunun değişkenlerine karşılık gelir dir_name.
CervEd

13

os.listdir()Belirli bir dizinde (hem dosyalar hem de dizinler için) bir isim listesi döndüren hangisini kullanabilirsiniz . Dosyalar ve dizinler arasında ayrım yapmanız gerekirse os.stat(), her ismi arayın .


9

Yalnızca en üst dizinden daha karmaşık gereksinimleriniz varsa (örneğin, VCS dizinlerini göz ardı etme vb.), Os.walk'un bunlar üzerinden tekrarlanmasını önlemek için dizin listesini de değiştirebilirsiniz.

yani:

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        dirs[:] = [d for d in dirs if is_good(d)]
        for f in files:
            do_stuff()

Not - listeyi yeniden düzenlemek yerine, değiştirmeye dikkat edin. Açıkçası os.walk, harici yeniden bağlama hakkında bir şey bilmiyor.


6
for path, dirs, files in os.walk('.'):
    print path, dirs, files
    del dirs[:] # go only one level deep

4

Aynı fikir listdir, ancak daha kısa:

[f for f in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, f))]

3

2 pensimi içeri atmak gibi hissettim.

baselevel = len(rootdir.split("\\"))
for subdirs, dirs, files in os.walk(rootdir):
    curlevel = len(subdirs.split("\\"))
    if curlevel <= baselevel + 1:
        [do stuff]

2

Python 3'te bunu yapabildim:

import os
dir = "/path/to/files/"

#List all files immediately under this folder:
print ( next( os.walk(dir) )[2] )

#List all folders immediately under this folder:
print ( next( os.walk(dir) )[1] )

Bu aynı zamanda Python 2 için de geçerlidir. İkinci seviyeye nasıl geçilir?

2

Python 3.5'ten beri os.scandiryerine kullanabilirsiniz os.listdir. Dizeler yerine, DirEntrykarşılığında bir nesne yineleyicisi alırsınız . Dokümanlardan:

scandir()Bunun yerine kullanmak , listdir()dosya türü veya dosya öznitelik bilgisine de ihtiyaç duyan kodun performansını önemli ölçüde artırabilir, çünkü DirEntryişletim sistemi bir dizini tararken bunu sağlarsa nesneler bu bilgiyi açığa çıkarır. Tüm DirEntryyöntemler bir sistem çağrısı gerçekleştirebilir, ancak is_dir()ve is_file()genellikle yalnızca sembolik bağlantılar için bir sistem çağrısı gerektirir; DirEntry.stat()her zaman Unix'te bir sistem çağrısı gerektirir, ancak Windows'taki sembolik bağlantılar için yalnızca bir tane gerektirir.

Nesnenin adına erişebilirsiniz, DirEntry.namebu da daha sonra çıktısına eşdeğerdir.os.listdir


1
Sadece "can" sen kullanmak gerekir kullanmak scandir()bir yöntem olduğu çok daha hızlı listdir(). Karşılaştırmaları burada görün: stackoverflow.com/a/40347279/2441026 .
user136036

1

Ayrıca şunları da yapabilirsiniz:

for path, subdirs, files in os.walk(dir_name):
    for name in files:
        if path == ".": #this will filter the files in the current directory
             #code here

2
Bu, tüm alt dizinler ve dosyalar arasında gereksiz yere döngü oluşturmaz mı?
Pieter

0

Ben böyle çözdüm

if recursive:
    items = os.walk(target_directory)
else:
    items = [next(os.walk(target_directory))]

...

0

Listdir kullanılırken bir yakalama vardır. Os.path.isdir (tanımlayıcı) mutlak bir yol olmalıdır. Alt dizinleri seçmek için şunları yaparsınız:

for dirname in os.listdir(rootdir):
  if os.path.isdir(os.path.join(rootdir, dirname)):
     print("I got a subdirectory: %s" % dirname)

Alternatif, testi os.path.join () olmadan yapmak için dizine geçmektir.


0

Bu pasajı kullanabilirsiniz

for root, dirs, files in os.walk(directory):
    if level > 0:
        # do some stuff
    else:
        break
    level-=1

0

bir dışlama listesi oluşturun, dizin yapısını atlamak için fnmatch kullanın ve işlemi yapın

excludes= ['a\*\b', 'c\d\e']
for root, directories, files in os.walk('Start_Folder'):
    if not any(fnmatch.fnmatch(nf_root, pattern) for pattern in excludes):
        for root, directories, files in os.walk(nf_root):
            ....
            do the process
            ....

'içerir' ile aynı:

if **any**(fnmatch.fnmatch(nf_root, pattern) for pattern in **includes**):

0

Neden basitçe rangeve os.walkile birlikte kullanmıyorsunuz zip? En iyi çözüm değil ama işe yarayacak.

Örneğin bunun gibi:

# your part before
for count, (root, dirs, files) in zip(range(0, 1), os.walk(dir_name)):
    # logic stuff
# your later part

Benim için python 3'te çalışıyor.

Ayrıca: A breakçok daha basit btw. (@Pieter'den gelen cevaba bakın)


0

Alex'in cevabında küçük bir değişiklik, ancak şunu kullanarak __next__():

print(next(os.walk('d:/'))[2]) veya print(os.walk('d:/').__next__()[2])

ile [2]varlık fileiçinde root, dirs, filediğer yanıtlar sözü


0

os.walk'un bulduğu her dizin için kök klasör değişir. Kök == dizin olup olmadığını kontrol etmeyi çözüyorum

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        if root == dir_name: #This only meet parent folder
            for f in files:
                if os.path.splitext(f)[1] in whitelist:
                    outputList.append(os.path.join(root, f))
                else:
                    self._email_to_("ignore")
    return outputList

0
import os

def listFiles(self, dir_name):
    names = []
    for root, directory, files in os.walk(dir_name):
        if root == dir_name:
            for name in files:
                names.append(name)
    return names

1
Merhaba Rich, Stack Overflow'a hoş geldiniz! Kısa vadeli sınırlı yardım sağlayabilecek bu kod parçacığı için teşekkür ederiz. Uygun bir açıklama , bunun neden soruna iyi bir çözüm olduğunu göstererek uzun vadeli değerini büyük ölçüde artıracak ve diğer benzer sorularla gelecekteki okuyucular için daha yararlı hale getirecektir. Yaptığınız varsayımlar da dahil olmak üzere bazı açıklamalar eklemek için lütfen yanıtınızı düzenleyin .
kenny_k
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.