Comment obtenir le dernier fichier dans un dossier à l'aide de python

126

J'ai besoin d'obtenir le dernier fichier d'un dossier en utilisant python. Lors de l'utilisation du code:

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

J'obtiens l'erreur ci-dessous:

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

garlapak
la source
2
Quel fichier essayez-vous de trouver? ajoutez votre code pertinent à la question.
Naeem Ul Wahhab du
1
Je devine pourquoi cela pourrait ne pas fonctionner pour vous: "fichiers" est-il une liste d'éléments de nom de fichier ou une seule chaîne de nom de fichier?
mpurg

Réponses:

323

Tout ce qui est attribué à la filesvariable est incorrect. Utilisez le code suivant.

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
la source
4
Et si, au lieu d'un fichier, je voulais trouver le dernier dossier créé / modifié?
Lien le
1
@Link le même code fonctionne pour cela. Si vous voulez vérifier son dossier ou non, vous pouvez vérifierif os.path.isdir(latest_file):
Marlon Abeykoon
6
Bizarre. J'ai dû utiliser "min" pour obtenir le dernier fichier. Certaines recherches ont laissé entendre que c'était spécifique au système d'exploitation.
Graeck
15
C'est une excellente réponse - MERCI! J'aime travailler avec des pathlib.Pathobjets plus qu'avec des chaînes et os.path. Avec les objets pathlib.Path, votre réponse devient: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Phil
4
@phil Vous pouvez toujours utiliser os.path.getctimecomme clé, même avec des Pathobjets.
Berislav Lopac
42
max(files, key = os.path.getctime)

est un code assez incomplet. C'est quoi files? C'est probablement une liste de noms de fichiers, sortant de os.listdir().

Mais cette liste ne répertorie que les parties du nom de fichier (aka "basenames"), car leur chemin est commun. Pour l'utiliser correctement, vous devez le combiner avec le chemin qui y mène (et utilisé pour l'obtenir).

Tels que (non testé):

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
la source
Je suis sûr que les contrevenants peuvent expliquer ce qui ne va pas exactement.
glglgl
3
Dunno, testé pour vous, cela semble fonctionner. En plus de cela, vous étiez le seul à vouloir expliquer un peu. La lecture de la réponse acceptée m'a fait penser que quelque chose de «glob» était nécessaire, alors que ce n'est absolument pas le cas. Merci
Arnaud P
4
@David Bien sûr. Insérez simplement if basename.endswith('.csv')dans la liste de compréhension.
glglgl
1
@BreakBadSP Si vous voulez de la flexibilité, vous avez raison. Si vous êtes limité à un certain répertoire, je ne vois pas comment le vôtre peut être plus efficace. Mais parfois, la lisibilité est plus importante que l'efficacité, la vôtre pourrait donc être meilleure dans ce sens.
glglgl
1
Merci pour cela, je l'ai utilisé dans tant de mes fonctions ETL!
Manakin
9

Je suggérerais d'utiliser à la glob.iglob()place du glob.glob(), car il est plus efficace.

glob.iglob () Renvoie un itérateur qui donne les mêmes valeurs que glob () sans les stocker toutes simultanément.

Ce qui signifie glob.iglob() seront plus efficaces.

J'utilise principalement le code ci-dessous pour trouver le dernier fichier correspondant à mon modèle:

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


REMARQUE: il existe des variantes de max fonction, en cas de recherche du dernier fichier, nous utiliserons la variante ci-dessous: max(iterable, *[, key, default])

qui doit être itérable afin que votre premier paramètre soit itérable. En cas de recherche d'un maximum de nombres, nous pouvons utiliser la variante ci-dessous:max (num1, num2, num3, *args[, key])

BreakBadSP
la source
1
J'aime ce max()genre. Dans mon cas, j'en ai utilisé un autre key=os.path.basenamecar les noms de fichiers avaient des horodatages.
MarkHu
4

Essayez de trier les éléments par heure de création. L'exemple ci-dessous trie les fichiers dans un dossier et obtient le premier élément qui est le plus récent.

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
la source
4

Je n'ai pas la réputation de commenter mais ctime de la réponse de Marlon Abeykoons n'a pas donné le résultat correct pour moi. L'utilisation de mtime fait cependant l'affaire. (clé = os.path.get m heure))

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

J'ai trouvé deux réponses à ce problème:

python os.path.getctime max ne renvoie pas la dernière différence entre python - getmtime () et getctime () dans le système unix

crlf
la source
1

(Modifié pour améliorer la réponse)

Définissez d'abord une fonction get_latest_file

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

Vous pouvez également utiliser une 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)

Si vous utilisez Python 3 , vous pouvez utiliser iglob à la place.

Code complet pour renvoyer le nom du dernier fichier:

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
la source
D'où avez-vous obtenu la JuniperAccessLog-standalone-FCL_VPNpièce?
glglgl
Cela échoue sur les fichiers de 0 longueur sous Windows 10.
Superdooperhero
1

J'ai essayé d'utiliser les suggestions ci-dessus et mon programme s'est écrasé, puis j'ai compris que le fichier que j'essayais d'identifier était utilisé et que lorsque j'essayais d'utiliser 'os.path.getctime', il s'est écrasé. ce qui a finalement fonctionné pour moi était:

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

ce code obtient l'objet rare entre les deux ensembles de listes de fichiers, ce n'est pas le plus élégant, et si plusieurs fichiers sont créés en même temps, il ne sera probablement pas stable

AlexFink
la source
1

Une méthode beaucoup plus rapide sur Windows (0.05s), appelez un script bat qui fait ceci:

get_latest.bat

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

\\directory\in\questionest le répertoire que vous souhaitez étudier.

get_latest.py

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

s'il trouve un fichier stdoutest le chemin etstderr est None.

Utilisez stdout.decode("utf-8").rstrip()pour obtenir la représentation sous forme de chaîne utilisable du nom de fichier.

ic_fl2
la source
Je ne sais pas pourquoi cela attire des votes, pour ceux qui doivent faire cette tâche rapidement, c'est la méthode la plus rapide que j'ai pu trouver. Et parfois, il est nécessaire de le faire très rapidement.
ic_fl2
Ayez un vote favorable. Je ne fais pas cela sous Windows, mais si vous recherchez de la vitesse, les autres réponses nécessitent une itération de tous les fichiers d'un répertoire. Donc, si les commandes shell de votre système d'exploitation qui spécifient un ordre de tri des fichiers répertoriés sont disponibles, l'extraction du premier ou du dernier résultat devrait être plus rapide.
Jim Hunziker
1
Merci en fait, je suis en fait plus préoccupé par une meilleure solution que celle-ci (comme en python tout aussi rapide mais pur), j'espérais donc que quelqu'un pourrait élaborer sur cela.
ic_fl2
2
Désolé, mais j'ai dû voter contre, et je vais vous donner la courtoisie d'expliquer les raisons. La principale raison est qu'il n'utilise pas python (pas multiplateforme) donc cassé à moins d'être exécuté sous Windows. Deuxièmement, ce n'est pas une "méthode plus rapide" (à moins que plus rapide signifie rapide et sale-pas-dérangeant-à-lire-les-docs) - la vente à un autre script est notoirement lente.
MarkHu
1
@MarkHu En fait, ce script est né de la nécessité de vérifier rapidement le contenu d'un gros dossier à partir d'un script python. Donc, dans ce cas, une méthode plus rapide signifie que le nom de fichier du dossier le plus récent est obtenu le plus rapidement (ou plus rapidement qu'une méthode python pure). N'hésitez pas à ajouter un script similaire pour Linux, probablement basé sur ls -Art | tail -n 1. Veuillez évaluer les performances d'une solution avant de faire des réclamations à son sujet.
ic_fl2
0

Je l'utilise dans Python 3, y compris la correspondance de motif sur le nom de fichier.

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
la source