2010-11-04 21 views
11

Tengo un directorio con 90K archivos en él. Esta es una cantidad de archivos absurdamente enorme que fallan las funciones como ls. Así que por supuesto, hace os.listdir() de mi secuencia de comandos python (Mac Python, versión 2.5); falla con OSError: [Errno 12] Cannot allocate memory: '.'Solución del problema OSError con os.listdir

La gente dirá "¡No coloque tantos archivos en un solo directorio! ¿Está loco?" - pero me gusta fingir que vivo en el futuro, un lugar brillante y brillante, donde tengo gigabytes de memoria a mi disposición, y no tengo que preocuparme demasiado por dónde exactamente van mis archivos, siempre y cuando haya óxido en mis platos giratorios.

Entonces, ¿hay una buena solución para este problema os.listdir()? He considerado simplemente bombardear a find, pero eso es un poco asqueroso, y desafortunadamente find es recursivo, sin la opción de maxdepth admitida en Mac OS X 10.6.

Aquí es lo que el os.listdir a través de los bombardeos a cabo para encontrar parece, más o menos:

def ls(directory): 
    import os 
    files = os.popen4('find %s' % directory)[1].read().rstrip().split('\n') 
    files.remove(directory) 
    return files # probably want to remove dir prefix from everything in here too 

Actualización:os.listdir() tiene éxito en Python 2.6.

+2

¿Cuál es el error que obtiene? De forma rutinaria utilizo 'os.listdir' para obtener listados de directorios con 50-100k archivos en ellos. 'os.listdir' es también la opción más rápida, ya que no' stat' de cada archivo en el directorio. – Seth

+0

@Seth, obtengo OSError: [Errno 12] No se puede asignar memoria: '.' –

+0

¿Aproximadamente cuántos archivos hay en este directorio? –

Respuesta

2
def ls(directory): 
    """full-featured solution, via wrapping find""" 
    import os 
    files = os.popen4('find %s' % directory)[1].read().rstrip().split('\n') 
    files.remove(directory) 
    n = len(directory) 
    if directory[-1] != os.path.sep: 
     n += 1 
    files = [f[n:] for f in files] # remove dir prefix 
    return [f for f in files if os.path.sep not in f] # remove files in sub-directories 
+1

¿Qué pasa con los votos bajos, ustedes? ? –

+0

Sí, funcionaría, pero no ayudará con el problema de rendimiento en archivos de 90k. –

+0

Estoy buscando algo que funcione, no me importa el rendimiento. Una solución de rendimiento que no funciona. 't a solution. –

4

Puede intentar ir un nivel más profundo y llamar directamente a opendir() y readdir() usando ctypes.

+0

Desesperado, pero si 'listdir' y' ls' fallan es lo único que se me ocurre – bobince

+0

Esto es tentador, pero el problema es que 'readdir' devuelve datos como' struct direct', y el diseño de th at es específico de la plataforma. Creo que la única forma * confiable * de implementar esto es con un módulo nativo. –

7

Estás accediendo a un artefacto histórico en Python: os.listdir debería devolver un iterador, no una matriz. Creo que esta función es anterior a los iteradores, es extraño que no se haya agregado os.xlistdir.

Esto tiene más efectos que solo el uso de memoria en directorios grandes. Incluso en un directorio con solo unos pocos miles de archivos, tendrá que esperar a que se complete todo el escaneo del directorio, y debe leer el directorio completo , incluso si la primera entrada es la que está buscando. .

esto es una falta muy evidente en Python: parece que hay sin unión al bajo nivel de opendir/readdir/fdopendir API, por lo que parece que ni siquiera es posible implementar esto por sí mismo sin necesidad de escribir un módulo nativo . Este es uno de esos casos en los que es un gran agujero en la biblioteca estándar que dudo de mí mismo y sospecho que simplemente no lo veo: hay enlaces de bajo nivel open, stat, etc., y esto está en la misma categoría

+0

Siempre es agradable ver downvotes misteriosos. Creo que es la penalización de "atreverse a criticar a Python". –

+1

'ImportError: Ningún módulo llamado criticar' – Seth

+0

Eso implicaría' ImportError: Ningún módulo llamado mejora'. –

2

Obtengo el mismo IOError en Apple Python 2.5.5 en 10.6 cuando lista un gran directorio. Funciona muy bien en Python2.6.

Python 2.5.5 (r255:77872, Sep 21 2010, 09:52:31) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import os 
>>> x = os.listdir('.') 
OSError: [Errno 12] Cannot allocate memory: '.' 

Esto parece ser un error en Python2.5. Consulte "os.listdir randomly fails on occasions when it shouldn't" y "Sloppy error checking in listdir() for Posix".

Cuestiones relacionadas