2010-12-09 11 views
8

1 milyon dosya içeren bir klasöre sahip oluyorum.Bir klasördeki dosyaları derhal işleme başlamak için bir akış olarak listeleme

Python veya diğer komut langage içinde, bu klasördeki dosyaları listeleme yaparken, hemen işlemine başlamak istiyorum.

zamanki fonksiyonları (Python os.listdir ...) engelliyor ve programım uzun zaman alabilir listenin sonunu beklemek zorunda.

Büyük klasörleri listelemenin en iyi yolu nedir?

+0

, sanırım, ama don:

Kaynak (. Örn FindFirstFileW ve FindNextFileW fonksiyonları ücretsiz stat bilgilerinde atmak çünkü DirEntry.stat(follow_symlinks=False) Windows üzerinde bir sistem çağrı yapar asla) Python'un standart kütüphanesinde mevcut olduklarına inanıyoruz. Dosya adlarında yapmayı planladığınız işlem nedir? –

cevap

12

Uygunsa, dizin yapınızı değiştirin; ancak değilse, use ctypes to call opendir and readdir.

İşte bu kodun bir kopyasıdır; Tüm yaptığım doğru girintili, try/finally bloğu ekleyin ve bir hatayı düzeltin. Hata ayıklamak zorunda kalabilirsiniz. Özellikle yapı düzeni. Bu kod taşınabilir değil olduğunu

Not. Windows'ta farklı işlevleri kullanmanız gerekir ve bence yapılar Unix'ten Unix'e kadar değişiyor.

#!/usr/bin/python 
""" 
An equivalent os.listdir but as a generator using ctypes 
""" 

from ctypes import CDLL, c_char_p, c_int, c_long, c_ushort, c_byte, c_char, Structure, POINTER 
from ctypes.util import find_library 

class c_dir(Structure): 
    """Opaque type for directory entries, corresponds to struct DIR""" 
    pass 
c_dir_p = POINTER(c_dir) 

class c_dirent(Structure): 
    """Directory entry""" 
    # FIXME not sure these are the exactly correct types! 
    _fields_ = (
     ('d_ino', c_long), # inode number 
     ('d_off', c_long), # offset to the next dirent 
     ('d_reclen', c_ushort), # length of this record 
     ('d_type', c_byte), # type of file; not supported by all file system types 
     ('d_name', c_char * 4096) # filename 
     ) 
c_dirent_p = POINTER(c_dirent) 

c_lib = CDLL(find_library("c")) 
opendir = c_lib.opendir 
opendir.argtypes = [c_char_p] 
opendir.restype = c_dir_p 

# FIXME Should probably use readdir_r here 
readdir = c_lib.readdir 
readdir.argtypes = [c_dir_p] 
readdir.restype = c_dirent_p 

closedir = c_lib.closedir 
closedir.argtypes = [c_dir_p] 
closedir.restype = c_int 

def listdir(path): 
    """ 
    A generator to return the names of files in the directory passed in 
    """ 
    dir_p = opendir(path) 
    try: 
     while True: 
      p = readdir(dir_p) 
      if not p: 
       break 
      name = p.contents.d_name 
      if name not in (".", ".."): 
       yield name 
    finally: 
     closedir(dir_p) 

if __name__ == "__main__": 
    for name in listdir("."): 
     print name 
+0

"c_dir_p" nerede tanımlandı? – jldupont

+0

Bunun eksik olduğundan emin olun 'c_dir_p = POINTER (c_dir)' – jdi

+0

Hata. Haklısın, ekleyeceğim. –

3

Bu kirli hissediyor ama hile yapmak gerekir:

def listdirx(dirname='.', cmd='ls'): 
    proc = subprocess.Popen([cmd, dirname], stdout=subprocess.PIPE) 
    filename = proc.stdout.readline() 
    while filename != '': 
     yield filename.rstrip('\n') 
     filename = proc.stdout.readline() 
    proc.communicate() 

Kullanımı: listdirx('/something/with/lots/of/files')

+0

Bu oldukça güzel – Thomas

+0

'ls' dosya adlarını, en azından varsayılan olarak sıralar. Bu yüzden onları os.listdir() 'den daha hızlı geri döndürmeye başlayacağını düşünmüyorum. 'Ls' tür değil yapmak için bir bayrak var mı? –

+2

'ls -f' sıralanmaz. '-f'' nin '-a' işaretini açtığını, böylece gizli dosyaları, gizli dizinleri,' 've' ..'yi filtrelemeye gerek duymayacaklarını unutmayın. –

0

İşte Windows üzerinde dosyası tarafından büyük bir dizin dosyası çapraz nasıl cevap!

beni Linux üzerinde yapılır ne sağlayacak bir Windows DLL için bir manyak, ancak hiçbir şans gibi arama yaptı.

Yani, tek yolun bana bu statik işlevleri gösterecektir kendi DLL oluşturmak için olduğu sonucuna ama sonra pywintypes hatırladım. Ve YEEY! Bu zaten orada yapıldı. Ve dahası, yineleyici bir işlev zaten uygulandı! Güzel!

Windows FindFirstFile ile DLL(), FindNextFile() ve FindClose() oralarda hâlâ olabilir ama onu bulamadık. Yani, ben pywintypes kullanılır.

DÜZENLEME: Kernel32.dll dosyasında düz göründüler. Lütfen ssokolow'un cevabına ve benim yorumuma bakın.

Bağımlılık için özür dilerim. Ama ... \ site paketleri \ win32 klasöründe ve nihai bağımlılıkları gelen win32file.pyd ayıklamak ve gerekirse Programınızla win32types ait bağımsız dağıtabilirsiniz düşünüyorum. Bunun nasıl arama ve bazı diğerleri de zaman

Bu soruyu buldum. İşte

:

How to copy first 100 files from a directory of thousands of files using python?

I (Jason Orendorff tarafından) ve burada takdim benim, Windows sürümü ile buradan listdir() Linux sürümü ile tam bir kod yayınlanmıştır.

Yani aşağı yukarı çapraz platform sürümünü isteyen herkes, oraya gitmek ya da iki cevaplara kendini birleştirir.

DÜZENLEME: Ya da daha iyisi, Python 3'te kullanım scandir modül veya os.scandir() (.5) ve aşağıdaki versiyonlar. Hataları ve diğer bazı şeyleri daha iyi idare eder. Google'da kapalı geliyor insanlar için

from win32file import FindFilesIterator 
import os 

def listdir (path): 
    """ 
    A generator to return the names of files in the directory passed in 
    """ 
    if "*" not in path and "?" not in path: 
     st = os.stat(path) # Raise an error if dir doesn't exist or access is denied to us 
     # Check if we got a dir or something else! 
     # Check gotten from stat.py (for fast checking): 
     if (st.st_mode & 0170000) != 0040000: 
      e = OSError() 
      e.errno = 20; e.filename = path; e.strerror = "Not a directory" 
      raise e 
     path = path.rstrip("\\/")+"\\*" 
    # Else: Decide that user knows what she/he is doing 
    for file in FindFilesIterator(path): 
     name = file[-2] 
     # Unfortunately, only drives (eg. C:) don't include "." and ".." in the list: 
     if name=="." and name=="..": continue 
     yield name 
2

, PEP 471 Python 3.5 standart kütüphanesine uygun bir çözüm eklendi ve Python için backported 2.6+ ve got 3.2+ PIP üzerinde scandir modül olarak.

Kaynak: https://stackoverflow.com/a/34922054/435253

Python 3.5+:

  • os.walk iyi performans için bu altyapıyı kullanmaya güncellendi.
  • os.scandir, DirEntry nesnelerinin üzerinde bir yineleyici döndürür.

Python 2.6/2.7 ve 3.2/3.3/3.4:

  • scandir.walkos.walk
  • scandir.scandir daha ölçülebilir versiyonu DirEntry nesnelerin üzerine bir yineleyici döndürür.

scandir() yineleyiciler opendir POSIX platformlarda/readdir ve Windows üzerinde FindFirstFileW/FindNextFileW sarın.

DirEntry nesnelerini döndürme noktası, yapılan sistem çağrılarının sayısını en aza indirmek için meta verilerin önbelleğe alınmasına izin vermektir. 'Sen POSIX fonksiyonları opendir/readdir istiyorum https://docs.python.org/3/library/os.html#os.scandir

+0

Gelişiminin 2013 yılında başladığı görülüyor. Fakat o zaman bunu bulamadım (2015). Gerçekten nasıl olduğunu bilmiyorum. Bu nedenle, myown çözümünü yazdım ve FindFirstFile'in kernel32.dll dosyasında olduğunu (scandirin kodunda) keşfetmesi beni hayal kırıklığına uğrattı. Bütün zaman burnumun önünde saklanıyor. Her iki sebepten dolayı kendimi bir çay kaşığı içinde boğmak için bir noktaya gittim, ancak bunun yerine yayınlarımı düzenlemeye karar verdim. : D İlk önce buraya geldin, bu yüzden +1! Tamam hala FindFirstFile() hakkında bilgi ekliyorum. : D – Dalen

İlgili konular