Cómo obtener el último archivo en una carpeta usando Python

126

Necesito obtener el último archivo de una carpeta usando python. Mientras usa el código:

max(files, key = os.path.getctime)

Recibo el siguiente error:

FileNotFoundError: [WinError 2] The system cannot find the file specified: 'a'

garlapak
fuente
2
¿Qué archivo intentas encontrar? agregue su código relevante a la pregunta.
Naeem Ul Wahhab
1
Supongo que puede que no funcione para usted: ¿"archivos" es una lista de elementos de nombre de archivo o una sola cadena de nombre de archivo?
mpurg

Respuestas:

323

Todo lo que se asigna a la filesvariable es incorrecto. Utilice el siguiente código.

import glob
import os

list_of_files = glob.glob('/path/to/folder/*') # * means all if need specific format then *.csv
latest_file = max(list_of_files, key=os.path.getctime)
print latest_file
Marlon Abeykoon
fuente
4
¿Qué pasa si en lugar de un archivo quiero encontrar la última carpeta creada / modificada?
Enlace
1
@Link, el mismo código funciona para eso. Si quieres comprobar si es una carpeta o no, puedes comprobarloif os.path.isdir(latest_file):
Marlon Abeykoon
6
Extraño. Tuve que usar "min" para obtener el archivo más reciente. Algunas búsquedas dieron a entender que es específico del sistema operativo.
Graeck
15
Esta es una excelente respuesta - ¡GRACIAS! Me gusta trabajar con pathlib.Pathobjetos más que cadenas y os.path. Con los objetos pathlib.Path, su respuesta se convierte en: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Phil
4
@phil Todavía puedes usarlo os.path.getctimecomo clave, incluso con Pathobjetos.
Berislav Lopac
42
max(files, key = os.path.getctime)

es un código bastante incompleto. ¿Qué es files? Probablemente sea una lista de nombres de archivos de la que se sale os.listdir().

Pero esta lista enumera solo las partes del nombre de archivo (también conocidas como "nombres de base"), porque su ruta es común. Para usarlo correctamente, debes combinarlo con el camino que lo lleva (y usado para obtenerlo).

Como (no probado):

def newest(path):
    files = os.listdir(path)
    paths = [os.path.join(path, basename) for basename in files]
    return max(paths, key=os.path.getctime)
glglgl
fuente
Estoy seguro de que los votantes negativos pueden explicar qué es exactamente lo que está mal.
glglgl
3
No sé, probado para ti, parece funcionar. Además de eso, fuiste el único al que le importó explicar un poco. Leer la respuesta aceptada me hizo pensar que se necesitaba algo 'global', mientras que no lo es en absoluto. Gracias
Arnaud P
4
@David Por supuesto. Simplemente inserte if basename.endswith('.csv')en la lista de comprensión.
glglgl
1
@BreakBadSP Si quieres flexibilidad, tienes razón. Si está restringido a un directorio determinado, no veo cómo el suyo puede ser más eficiente. Pero a veces, la legibilidad es más importante que la eficiencia, por lo que la suya podría ser mejor en ese sentido.
glglgl
1
Gracias por esto, ¡lo he usado en muchas de mis funciones ETL!
Manakin
9

Sugeriría usar en glob.iglob()lugar de glob.glob(), ya que es más eficiente.

glob.iglob () Devuelve un iterador que produce los mismos valores que glob () sin almacenarlos todos simultáneamente.

Lo que significa glob.iglob() serán más eficientes.

Utilizo principalmente el siguiente código para encontrar el último archivo que coincida con mi patrón:

LatestFile = max(glob.iglob(fileNamePattern),key=os.path.getctime)


NOTA: Hay variantes de max función, en caso de encontrar el último archivo, usaremos la siguiente variante: max(iterable, *[, key, default])

que necesita iterable por lo que su primer parámetro debería ser iterable. En caso de encontrar un máximo de números, podemos usar la variante beow:max (num1, num2, num3, *args[, key])

BreakBadSP
fuente
1
Me gusta este max()tipo. En mi caso, utilicé uno diferente key=os.path.basenameya que los nombres de archivo tenían marcas de tiempo.
MarkHu
4

Intente ordenar los elementos por hora de creación. El siguiente ejemplo ordena los archivos en una carpeta y obtiene el primer elemento que es el más reciente.

import glob
import os

files_path = os.path.join(folder, '*')
files = sorted(
    glob.iglob(files_path), key=os.path.getctime, reverse=True) 
print files[0]
turkus
fuente
4

Me falta la reputación para comentar, pero el tiempo de respuesta de Marlon Abeykoon no me dio el resultado correcto. Sin embargo, usar mtime funciona. (clave = os.path.get m time))

import glob
import os

list_of_files = glob.glob('/path/to/folder/*') # * means all if need specific format then *.csv
latest_file = max(list_of_files, key=os.path.getmtime)
print latest_file

Encontré dos respuestas para ese problema:

python os.path.getctime max no devuelve la última diferencia entre python - getmtime () y getctime () en el sistema Unix

crlf
fuente
1

(Editado para mejorar la respuesta)

Primero defina una función get_latest_file

def get_latest_file(path, *paths):
    fullpath = os.path.join(path, paths)
    ...
get_latest_file('example', 'files','randomtext011.*.txt')

¡También puede usar una cadena de documentos!

def get_latest_file(path, *paths):
    """Returns the name of the latest (most recent) file 
    of the joined path(s)"""
    fullpath = os.path.join(path, *paths)

Si usa Python 3 , puede usar iglob en su lugar.

Código completo para devolver el nombre del último archivo:

def get_latest_file(path, *paths):
    """Returns the name of the latest (most recent) file 
    of the joined path(s)"""
    fullpath = os.path.join(path, *paths)
    files = glob.glob(fullpath)  # You may use iglob in Python3
    if not files:                # I prefer using the negation
        return None                      # because it behaves like a shortcut
    latest_file = max(files, key=os.path.getctime)
    _, filename = os.path.split(latest_file)
    return filename
Naeem Ul Wahhab
fuente
¿De dónde sacaste la JuniperAccessLog-standalone-FCL_VPNpieza?
glglgl
Esto falla en archivos de longitud 0 en Windows 10.
Superdooperhero
1

Intenté usar las sugerencias anteriores y mi programa se bloqueó, entonces descubrí que se usó el archivo que estoy tratando de identificar y cuando intenté usar 'os.path.getctime' se bloqueó. lo que finalmente funcionó para mí fue:

    files_before = glob.glob(os.path.join(my_path,'*'))
    **code where new file is created**
    new_file = set(files_before).symmetric_difference(set(glob.glob(os.path.join(my_path,'*'))))

este código obtiene el objeto poco común entre los dos conjuntos de listas de archivos, no es el más elegante, y si se crean varios archivos al mismo tiempo, probablemente no será estable

AlexFink
fuente
1

Un método mucho más rápido en Windows (0.05s), llame a un script bat que haga esto:

get_latest.bat

@echo off
for /f %%i in ('dir \\directory\in\question /b/a-d/od/t:c') do set LAST=%%i
%LAST%

dónde \\directory\in\questionestá el directorio que desea investigar.

get_latest.py

from subprocess import Popen, PIPE
p = Popen("get_latest.bat", shell=True, stdout=PIPE,)
stdout, stderr = p.communicate()
print(stdout, stderr)

si encuentra un archivo stdoutes la ruta ystderr es Ninguno.

Úselo stdout.decode("utf-8").rstrip()para obtener la representación de cadena utilizable del nombre del archivo.

ic_fl2
fuente
No estoy seguro de por qué esto atrae votos negativos, para aquellos que necesitan hacer esta tarea rápidamente, este es el método más rápido que pude encontrar. Y a veces es necesario hacer esto muy rápidamente.
ic_fl2
Tener un voto a favor. No estoy haciendo esto en Windows, pero si está buscando velocidad, las otras respuestas requieren una iteración de todos los archivos en un directorio. Entonces, si los comandos de shell en su sistema operativo que especifican un orden de clasificación de los archivos enumerados están disponibles, extraer el primer o el último resultado debería ser más rápido.
Jim Hunziker
1
Gracias, en realidad estoy más preocupado por una solución mejor que esta (como en Python igualmente rápido pero puro), así que esperaba que alguien pudiera explicarlo con más detalle.
ic_fl2
2
Lo siento, pero tuve que votar en contra y te daré la cortesía de explicar las razones. La principal razón es que no está usando Python (no es multiplataforma), por lo tanto está roto a menos que se ejecute en Windows. En segundo lugar, este no es un "método más rápido" (a menos que más rápido signifique rápido-y-sucio-sin-molestar-en-leer-documentos) - la conversión a otro script es notoriamente lento.
MarkHu
1
@MarkHu En realidad, este script nació de la necesidad de verificar rápidamente el contenido de una carpeta grande desde un script de Python. Entonces, en este caso, el método más rápido significa obtener el nombre de archivo de la carpeta más nueva más rápido (o más rápido que un método de Python puro). Siéntase libre de agregar un script similar para Linux, probablemente basado en ls -Art | tail -n 1. Evalúe el rendimiento de una solución antes de hacer afirmaciones al respecto.
ic_fl2
0

He estado usando esto en Python 3, incluida la coincidencia de patrones en el nombre del archivo.

from pathlib import Path

def latest_file(path: Path, pattern: str = "*"):
    files = path.glob(pattern)
    return max(files, key=lambda x: x.stat().st_ctime)
Jamie Bull
fuente