Come ottenere il file più recente in una cartella utilizzando python


126

Ho bisogno di ottenere l'ultimo file di una cartella utilizzando Python. Durante l'utilizzo del codice:

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

Ricevo l'errore seguente:

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


2
Quale file stai cercando di trovare? aggiungi il tuo codice pertinente alla domanda.
Naeem Ul Wahhab

1
Immagino perché potrebbe non funzionare per te: "files" è un elenco di elementi di nomi di file o una singola stringa di nomi di file?
mpurg

Risposte:


323

Qualunque cosa sia assegnata alla filesvariabile non è corretta. Usa il codice seguente.

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

4
E se invece di un file volessi trovare l'ultima cartella creata / modificata?
Link

1
@Link lo stesso codice funziona per quello. Se vuoi controllare è una cartella o non puoi controllareif os.path.isdir(latest_file):
Marlon Abeykoon

6
Strano. Ho dovuto usare "min" per ottenere il file più recente. Alcune ricerche in giro hanno suggerito che è specifico del sistema operativo.
Graeck

15
Questa è un'ottima risposta - GRAZIE! Mi piace lavorare con gli pathlib.Pathoggetti più che con stringhe e os.path. Con pathlib.Path oggetti la tua risposta diventa: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Phil

4
@phil Puoi ancora usare os.path.getctimecome chiave, anche con Pathoggetti.
Berislav Lopac

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

è un codice abbastanza incompleto. Che cos'è files? Probabilmente è un elenco di nomi di file, provenienti da os.listdir().

Ma questo elenco elenca solo le parti del nome del file (aka "nomi di base"), perché il loro percorso è comune. Per usarlo correttamente, devi combinarlo con il percorso che conduce ad esso (e utilizzato per ottenerlo).

Ad esempio (non testato):

def newest(path):
    files = os.listdir(path)
    paths = [os.path.join(path, basename) for basename in files]
    return max(paths, key=os.path.getctime)

Sono sicuro che i downvoters possano spiegare cosa c'è che non va.
glglgl

3
Boh, testato per te, sembra funzionare. Inoltre, eri l'unico a cui interessava spiegare un po '. Leggere la risposta accettata mi ha fatto pensare che fosse necessaria la cosa "glob", mentre non lo è assolutamente. Grazie
Arnaud P

4
@David Ovviamente. Basta inserire if basename.endswith('.csv')nella lista di comprensione.
glglgl

1
@BreakBadSP Se vuoi flessibilità, hai ragione. Se sei limitato a una determinata directory, non vedo come la tua possa essere più efficiente. Ma a volte, la leggibilità è più importante dell'efficienza, quindi la tua potrebbe davvero essere migliore in questo senso.
glglgl

1
Grazie per questo, l'ho usato in tante delle mie funzioni ETL!
Manakin

9

Suggerirei di utilizzare al glob.iglob()posto di glob.glob(), poiché è più efficiente.

glob.iglob () Restituisce un iteratore che restituisce gli stessi valori di glob () senza memorizzarli tutti contemporaneamente.

Che significa glob.iglob() che sarà più efficiente.

Uso principalmente il codice seguente per trovare l'ultimo file corrispondente al mio modello:

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


NOTA: ci sono varianti di maxfunzione, in caso di trovare il file più recente useremo la seguente variante: max(iterable, *[, key, default])

che necessita di iterabilità, quindi il tuo primo parametro dovrebbe essere iterabile. In caso di trovare il numero massimo di numeri possiamo usare la variante beow:max (num1, num2, num3, *args[, key])


1
Mi piace questo max()tipo. Nel mio caso, ho usato un diverso key=os.path.basenamepoiché i nomi dei file avevano timestamp.
MarkHu

4

Prova a ordinare gli elementi in base all'ora di creazione. L'esempio seguente ordina i file in una cartella e ottiene il primo elemento che è l'ultimo.

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]

4

Mi manca la reputazione per commentare ma il tempo della risposta di Marlon Abeykoons non ha dato il risultato corretto per me. Usare mtime però fa il trucco. (chiave = 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

Ho trovato due risposte per quel problema:

python os.path.getctime max non restituisce l'ultima differenza tra python - getmtime () e getctime () nel sistema unix


1

(Modificato per migliorare la risposta)

Definisci prima una funzione get_latest_file

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

Puoi anche usare una docstring!

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)

Se usi Python 3 , puoi invece usare iglob .

Codice completo per restituire il nome del file più recente:

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

Da dove hai preso la JuniperAccessLog-standalone-FCL_VPNparte?
glglgl

Questo fallisce su file di lunghezza 0 sotto Windows 10.
Superdooperhero

1

Ho provato a utilizzare i suggerimenti di cui sopra e il mio programma si è bloccato, poi ho capito che il file che sto cercando di identificare è stato utilizzato e quando ho provato a utilizzare 'os.path.getctime' si è bloccato. quello che alla fine ha funzionato per me è stato:

    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,'*'))))

questo codice ottiene l'oggetto insolito tra i due gruppi di elenchi di file non è il piùelegante, e se vengono creati più file contemporaneamente probabilmente non sarà stabile


1

Un metodo molto più veloce su Windows (0.05s), chiama uno script bat che fa questo:

get_latest.bat

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

dov'è \\directory\in\questionla directory che desideri esaminare.

get_latest.py

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

se trova un file stdoutè il percorso estderr è Nessuno.

Utilizzare stdout.decode("utf-8").rstrip()per ottenere la rappresentazione di stringa utilizzabile del nome file.


Non sono sicuro del motivo per cui questo attirare voti negativi, per coloro che hanno bisogno di svolgere questo compito rapidamente questo è il metodo più veloce che ho trovato. E a volte è necessario farlo molto rapidamente.
ic_fl2

Avere un voto positivo. Non lo sto facendo in Windows, ma se stai cercando velocità, le altre risposte richiedono un'iterazione di tutti i file in una directory. Quindi, se sono disponibili comandi della shell nel sistema operativo che specificano un ordinamento dei file elencati, estrarre il primo o l'ultimo risultato dovrebbe essere più veloce.
Jim Hunziker

1
Grazie, in realtà sono più interessato a una soluzione migliore di questa (come in un pitone altrettanto veloce ma puro), quindi speravo che qualcuno potesse elaborarlo.
ic_fl2

2
Scusa, ma ho dovuto votare in negativo e ti darò la cortesia di spiegare i motivi. Il motivo principale è che non utilizza python (non multipiattaforma) quindi non funzionante a meno che non venga eseguito sotto Windows. In secondo luogo, questo non è un "metodo più veloce" (a meno che più veloce non significhi veloce-e-sporco-che-non-si-preoccupa-di-leggere-documenti) - lo shelling a un altro script è notoriamente lento.
MarkHu

1
@MarkHu In realtà questo script è nato dalla necessità di controllare rapidamente il contenuto di una grande cartella da uno script Python. Quindi in questo caso il metodo più veloce significa, ottiene il nome del file della cartella più recente il più veloce (o più veloce di un metodo Python puro). Sentiti libero di aggiungere uno script simile per Linux, probabilmente basato su ls -Art | tail -n 1. Si prega di valutare le prestazioni di una soluzione prima di fare reclami in merito.
ic_fl2

0

L'ho usato in Python 3, incluso il pattern matching sul nome del file.

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.