Encontrar un archivo en python

Tengo un archivo que puede estar en un lugar diferente en la máquina de cada usuario. ¿Hay una manera de implementar una búsqueda del archivo? ¿Una manera de que pueda pasar el nombre del archivo y el árbol del directorio para buscar?

Pregunta hecha hace 14 años, 3 meses, 14 días - Por binarybard


11 Respuestas:

  • Os.walk es la respuesta, esto encontrará el primer partido:

    import os
    
    def find(name, path):
        for root, dirs, files in os.walk(path):
            if name in files:
                return os.path.join(root, name)
    

    Y esto encontrará todos los partidos:

    def find_all(name, path):
        result = []
        for root, dirs, files in os.walk(path):
            if name in files:
                result.append(os.path.join(root, name))
        return result
    

    Y esto coincidirá con un patrón:

    import os, fnmatch
    def find(pattern, path):
        result = []
        for root, dirs, files in os.walk(path):
            for name in files:
                if fnmatch.fnmatch(name, pattern):
                    result.append(os.path.join(root, name))
        return result
    
    find('*.txt', '/path/to/dir')
    

    Respondida el Nov 12, 2009 a las 19:27 - por quantumquill

    Votos positivos: 0 | Votos negativos: 0

  • En Python 3.4 o más nuevo se puede utilizar pathlib para hacer reluciente recursivo:

    >>> import pathlib
    >>> sorted(pathlib.Path('.').glob('**/*.py'))
    [PosixPath('build/lib/pathlib.py'),
     PosixPath('docs/conf.py'),
     PosixPath('pathlib.py'),
     PosixPath('setup.py'),
     PosixPath('test_pathlib.py')]
    

    Referencia: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob

    En Python 3.5 o más nuevo también se puede hacer palpitante recurrente como este:

    >>> import glob
    >>> glob.glob('**/*.txt', recursive=True)
    ['2.txt', 'sub/3.txt']
    

    Referencia: https://docs.python.org/3/library/glob.html#glob.glob

    Respondida el Nov 12, 2009 a las 19:34 - por codecrusaderx58e2

    Votos positivos: 0 | Votos negativos: 0

  • Usé una versión de os.walk y en un directorio más grande consiguió tiempos alrededor de 3.5 segundos. Traté de dos soluciones aleatorias sin gran mejora, y luego simplemente lo hice:

    paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
    

    Mientras es sólo POSIX, tengo 0,25 segundos.

    A partir de esto, creo que es totalmente posible optimizar la búsqueda completa mucho de una manera independiente de la plataforma, pero aquí es donde detuve la investigación.

    Respondida el Nov 12, 2009 a las 19:40 - por byteninja8245

    Votos positivos: 0 | Votos negativos: 0

  • Si está usando Python en Ubuntu y sólo quiere que funcione en Ubuntu de una manera sustancialmente más rápida es el uso de la terminal locate programa como este.

    import subprocess
    
    def find_files(file_name):
        command = ['locate', file_name]
    
        output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
        output = output.decode()
    
        search_results = output.split('\n')
    
        return search_results
    

    search_results es un list de las vías de archivo absolutas. Esto es 10.000 veces más rápido que los métodos anteriores y para una búsqueda que he hecho fue ~72.000 veces más rápido.

    Respondida el Nov 12, 2009 a las 19:49 - por devninjax

    Votos positivos: 0 | Votos negativos: 0

  • Si usted está trabajando con Python 2 usted tiene un problema con la recidiva infinita en las ventanas causadas por similitudes auto-referentes.

    Este script evitará seguirlos. Note que esto es Ventanas específicas!

    import os
    from scandir import scandir
    import ctypes
    
    def is_sym_link(path):
        # http://stackoverflow.com/a/35915819
        FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
        return os.path.isdir(path) and (ctypes.windll.kernel32.GetFileAttributesW(unicode(path)) & FILE_ATTRIBUTE_REPARSE_POINT)
    
    def find(base, filenames):
        hits = []
    
        def find_in_dir_subdir(direc):
            content = scandir(direc)
            for entry in content:
                if entry.name in filenames:
                    hits.append(os.path.join(direc, entry.name))
    
                elif entry.is_dir() and not is_sym_link(os.path.join(direc, entry.name)):
                    try:
                        find_in_dir_subdir(os.path.join(direc, entry.name))
                    except UnicodeDecodeError:
                        print "Could not resolve " + os.path.join(direc, entry.name)
                        continue
    
        if not os.path.exists(base):
            return
        else:
            find_in_dir_subdir(base)
    
        return hits
    

    Devuelve una lista con todas las rutas que apuntan a archivos en la lista de nombres de archivo. Usage:

    find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
    

    Respondida el Nov 12, 2009 a las 19:58 - por webweaverx

    Votos positivos: 0 | Votos negativos: 0

  • A continuación utilizamos un argumento booleano "primero" para cambiar entre el primer partido y todos los partidos (un defecto que es equivalente a "find . -name file"):

    import  os
    
    def find(root, file, first=False):
        for d, subD, f in os.walk(root):
            if file in f:
                print("{0} : {1}".format(file, d))
                if first == True:
                    break 
    

    Respondida el Nov 12, 2009 a las 20:07 - por codecanvas

    Votos positivos: 0 | Votos negativos: 0

  • La respuesta es muy similar a la existente, pero ligeramente optimizada.

    Para que pueda encontrar cualquier archivo o carpeta por patrón:

    def iter_all(pattern, path):
        return (
            os.path.join(root, entry)
            for root, dirs, files in os.walk(path)
            for entry in dirs + files
            if pattern.match(entry)
        )
    

    o por subestring:

    def iter_all(substring, path):
        return (
            os.path.join(root, entry)
            for root, dirs, files in os.walk(path)
            for entry in dirs + files
            if substring in entry
        )
    

    o usando un predicado:

    def iter_all(predicate, path):
        return (
            os.path.join(root, entry)
            for root, dirs, files in os.walk(path)
            for entry in dirs + files
            if predicate(entry)
        )
    

    para buscar sólo archivos o sólo carpetas - reemplazar “dirs + archivos”, por ejemplo, con sólo “dirs” o sólo “files”, dependiendo de lo que necesite.

    Saludos.

    Respondida el Nov 12, 2009 a las 20:12 - por codesculptor3f6e

    Votos positivos: 0 | Votos negativos: 0

  • La respuesta de SARose funcionó para mí hasta que me actualicé de Ubuntu 20.04 LTS. El ligero cambio que hice a su código hace que funcione en la última versión de Ubuntu.

    import subprocess
    
    def find_files(file_name):
        command = ['locate'+ ' ' + file_name]
        output = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]
        output = output.decode()
        search_results = output.split('\n')
        return search_results
    

    Respondida el Nov 12, 2009 a las 20:20 - por codejuggernaut

    Votos positivos: 0 | Votos negativos: 0

  • Las respuestas de @F.M.F tienen algunos problemas en esta versión, así que hice algunos ajustes para hacerlo funcionar.

    import os
    from os import scandir
    import ctypes
    
    def is_sym_link(path):
        # http://stackoverflow.com/a/35915819
        FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
        return os.path.isdir(path) and (ctypes.windll.kernel32.GetFileAttributesW(str(path)) & FILE_ATTRIBUTE_REPARSE_POINT)
    
    def find(base, filenames):
        hits = []
    
        def find_in_dir_subdir(direc):
            content = scandir(direc)
            for entry in content:
                if entry.name in filenames:
                    hits.append(os.path.join(direc, entry.name))
    
                elif entry.is_dir() and not is_sym_link(os.path.join(direc, entry.name)):
                    try:
                        find_in_dir_subdir(os.path.join(direc, entry.name))
                    except UnicodeDecodeError:
                        print("Could not resolve " + os.path.join(direc, entry.name))
                        continue
                    except PermissionError:
                        print("Skipped " + os.path.join(direc, entry.name) + ". I lacked permission to navigate")
                        continue
    
        if not os.path.exists(base):
            return
        else:
            find_in_dir_subdir(base)
    
        return hits
    

    unicode() fue cambiado a str() en Python 3, así que hice ese ajuste (línea 8)

    También añadí (en la línea 25) y excepción a PermissionError. De esta manera, el programa no parará si encuentra una carpeta que no puede acceder.

    Finalmente, me gustaría dar un pequeño aviso. Al ejecutar el programa, incluso si usted está buscando un solo archivo/directorio, asegúrese de pasarlo como una lista. De lo contrario, obtendrá muchas respuestas que no necesariamente coinciden con su búsqueda.

    ejemplo de uso:

    encontrar("C:\", ["Python", "Homework"])

    o

    encontrar("C:\", ["Homework"])

    pero, por ejemplo: find("C:\", "Homework") dará respuestas no deseadas.

    Estaría mintiendo si dijera que sé por qué sucede esto. De nuevo, este no es mi código y acabo de hacer los ajustes que necesitaba para que funcionara. Todo el crédito debe ir a @F.M.F.

    Respondida el Nov 12, 2009 a las 20:25 - por techtactician

    Votos positivos: 0 | Votos negativos: 0

  • Sí, puedes usar el módulo os de Python para buscar un archivo en un directorio determinado, o incluso en toda la estructura de directorios de la máquina. Aquí te dejo un ejemplo de cómo podrías implementar esta búsqueda:

    python
    import os
    
    def buscar_archivo(nombre_archivo, directorio):
        for root, dirs, files in os.walk(directorio):
            if nombre_archivo in files:
                ruta_archivo = os.path.join(root, nombre_archivo)
                return ruta_archivo
        return None
    
    

    Ejemplo de uso

    nombre_archivo = "ejemplo.txt" directorio = "/ruta/del/directorio/a/buscar" ruta_encontrada = buscar_archivo(nombre_archivo, directorio) if ruta_encontrada: print("El archivo se encontró en:", ruta_encontrada) else: print("El archivo no se encontró en el directorio especificado.")

    En este código, la función buscar_archivo recibe el nombre del archivo que deseas buscar y el directorio raíz desde donde empezará la búsqueda. Luego, utiliza os.walk para recorrer recursivamente todos los director

    Respondida el Nov 13, 2009 a las 19:27 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Sí, puedes utilizar la función os.walk de Python para encontrar un archivo en un árbol de directorios. Esta función toma un directorio inicial y recorre recursivamente todos los archivos y subdirectorios dentro de ese directorio. A continuación, puedes utilizar la función os.path.isfile para comprobar si un elemento de la lista devuelta por os.walk es un archivo.

    Aquí tienes un ejemplo de cómo hacerlo:

    python
    import os
    
    def find_file(name, path):
        for root, directories, files in os.walk(path):
            if name in files:
                return os.path.join(root, name)
    

    Esta función toma dos parámetros: name, que es el nombre del archivo que deseas encontrar, y path, que es el directorio inicial a partir del cual deseas buscar. La función devuelve la ruta completa del archivo si lo encuentra, o None si no lo encuentra.

    También puedes utilizar la función glob.glob para encontrar archivos en un árbol de directorios. Esta función toma un patrón de nombre de archivo (como *.txt) y devuelve una lista de todos los archivos que coinciden con ese patrón en el directorio especificado.

    Aquí tienes un ejemplo de cómo hacerlo:

    python
    import glob
    
    def find_file(name, path):
        return glob.glob(os.path.join(path, name))
    

    Esta función toma dos parámetros: name, que es el nombre del archivo que deseas encontrar, y path, que es el directorio inicial a partir del cual deseas buscar. La función devuelve una lista de todas las rutas completas de los archivos que coinciden con el patrón de nombre de archivo especificado.

    Ten en cuenta que la función glob.glob solo busca archivos en el directorio especificado, no en sus subdirectorios. Si deseas buscar archivos en subdirectorios, debes utilizar la función os.walk.

    Respondida el Nov 13, 2009 a las 19:31 - por Gemini

    Votos positivos: 0 | Votos negativos: 0