Jak uzyskać najnowszy plik w folderze za pomocą języka Python

126

Potrzebuję najnowszego pliku folderu przy użyciu języka Python. Podczas korzystania z kodu:

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

Otrzymuję następujący błąd:

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

garlapak
źródło
2
Który plik próbujesz znaleźć? dodaj swój odpowiedni kod do quesiton.
Naeem Ul Wahhab
1
Zgaduję, dlaczego to może nie działać dla Ciebie: czy „pliki” to lista elementów nazwy pliku, czy pojedynczy ciąg znaków?
mpurg,

Odpowiedzi:

323

Cokolwiek jest przypisane do fileszmiennej, jest nieprawidłowe. Użyj poniższego kodu.

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
źródło
4
Co jeśli zamiast pliku chcę znaleźć ostatnio utworzony / zmodyfikowany folder?
Link
1
@Link służy do tego ten sam kod. Jeśli chcesz sprawdzić folder, czy nie, możesz to sprawdzićif os.path.isdir(latest_file):
Marlon Abeykoon
6
Dziwne. Musiałem użyć „min”, aby pobrać najnowszy plik. Niektóre wyszukiwania sugerują, że jest to specyficzne dla systemu operacyjnego.
Graeck
15
To doskonała odpowiedź - DZIĘKUJEMY! Wolę pracować z pathlib.Pathobiektami niż ze stringami i os.path. W przypadku obiektów pathlib.Path odpowiedź brzmi: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Phil
4
@phil Nadal możesz używać os.path.getctimejako klucza, nawet w przypadku Pathobiektów.
Berislav Lopac
42
max(files, key = os.path.getctime)

jest dość niekompletnym kodem. Co to jest files? Prawdopodobnie jest to lista nazw plików, wychodząca z os.listdir().

Ale ta lista zawiera tylko części nazw plików (znane również jako „basenames”), ponieważ ich ścieżka jest wspólna. Aby poprawnie z niej korzystać musisz połączyć ją ze ścieżką do niej prowadzącą (i wykorzystaną do jej zdobycia).

Takich jak (nieprzetestowane):

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
źródło
Jestem pewien, że osoby negatywnie nastawione potrafią wyjaśnić, co jest nie tak.
glglgl
3
Nie wiem, przetestowane dla ciebie, wydaje się, że działa. Poza tym tylko ty chciałeś trochę wyjaśnić. Po przeczytaniu zaakceptowanej odpowiedzi pomyślałem, że „glob” jest potrzebny, a absolutnie nie. Dzięki
Arnaud P
4
@David Oczywiście. Po prostu wstaw if basename.endswith('.csv')do rozumienia listy.
glglgl
1
@BreakBadSP Jeśli chcesz elastyczności, masz rację. Jeśli jesteś ograniczony do określonego katalogu, nie widzę, jak twój może być bardziej wydajny. Ale czasami czytelność jest ważniejsza niż wydajność, więc Twoja może być lepsza w tym sensie.
glglgl
1
Dzięki za to, użyłem tego w wielu moich funkcjach ETL!
Manakin
9

Sugerowałbym użycie glob.iglob()zamiast glob.glob(), ponieważ jest bardziej wydajny.

glob.iglob () Zwraca iterator, który zwraca te same wartości co glob () bez faktycznego przechowywania ich wszystkich jednocześnie.

Co oznacza, glob.iglob()że będzie bardziej wydajny.

Najczęściej używam poniższego kodu, aby znaleźć najnowszy plik pasujący do mojego wzorca:

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


UWAGA: istnieją warianty maxfunkcji, w przypadku znalezienia najnowszego pliku użyjemy poniższego wariantu: max(iterable, *[, key, default])

który wymaga iterowalności, więc pierwszy parametr powinien być iterowalny. W przypadku znalezienia max of nums możemy skorzystać z wariantu beow:max (num1, num2, num3, *args[, key])

BreakBadSP
źródło
1
Podoba mi się ten max()rodzaj. W moim przypadku użyłem innego, key=os.path.basenameponieważ nazwy plików zawierały sygnatury czasowe.
MarkHu
4

Spróbuj posortować elementy według czasu utworzenia. Przykład poniżej sortuje pliki w folderze i pobiera pierwszy element, który jest najnowszy.

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
źródło
4

Brakuje mi reputacji do komentowania, ale ctime z odpowiedzi Marlona Abejkoona nie dał mi prawidłowego wyniku. Jednak użycie mtime załatwia sprawę. (klucz = os.path.get m czas))

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

Znalazłem dwie odpowiedzi na ten problem:

python os.path.getctime max nie zwraca najnowszej Różnica między python - getmtime () i getctime () w systemie unix

crlf
źródło
1

(Zredagowano, aby poprawić odpowiedź)

Najpierw zdefiniuj funkcję get_latest_file

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

Możesz także użyć sznurka!

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)

Jeśli używasz Pythona 3 , możesz zamiast tego użyć iglob .

Uzupełnij kod, aby zwrócić nazwę najnowszego pliku:

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
źródło
Skąd masz tę JuniperAccessLog-standalone-FCL_VPNczęść?
glglgl
To kończy się niepowodzeniem w przypadku plików o długości 0 w systemie Windows 10.
Superdooperhero,
1

Próbowałem skorzystać z powyższych sugestii i mój program się zawiesił, ale zorientowałem się, że plik, który próbuję zidentyfikować, został użyty, a podczas próby użycia „os.path.getctime” uległ awarii. co w końcu zadziałało dla mnie to:

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

ten kod pobiera nietypowy obiekt między dwoma zestawami list plików nie jest to najbardziej eleganckie i jeśli wiele plików jest tworzonych w tym samym czasie, prawdopodobnie nie będzie stabilny

AlexFink
źródło
1

Znacznie szybsza metoda w systemie Windows (0,05 s), wywołaj skrypt nietoperza, który robi to:

get_latest.bat

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

gdzie \\directory\in\questionjest katalog, który chcesz zbadać.

get_latest.py

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

jeśli znajdzie plik, stdoutjest ścieżką i stderrma wartość Brak.

Użyj, stdout.decode("utf-8").rstrip()aby uzyskać użyteczną reprezentację ciągu nazwy pliku.

ic_fl2
źródło
Nie jestem pewien, dlaczego to przyciąga głosy, ponieważ dla tych, którzy muszą wykonać to zadanie szybko, jest to najszybsza metoda, jaką znalazłem. Czasami trzeba to zrobić bardzo szybko.
ic_fl2
Głosuj za. Nie robię tego w systemie Windows, ale jeśli szukasz szybkości, inne odpowiedzi wymagają iteracji wszystkich plików w katalogu. Jeśli więc polecenia powłoki w systemie operacyjnym, które określają porządek sortowania wymienionych plików, są dostępne, pobranie pierwszego lub ostatniego wyniku powinno być szybsze.
Jim Hunziker
1
Dzięki, tak naprawdę bardziej interesuje mnie lepsze rozwiązanie niż to (jak w podobnie szybkim, ale czystym Pythonie), więc miałem nadzieję, że ktoś mógłby to rozwinąć.
ic_fl2
2
Przepraszam, ale musiałem zagłosować przeciw, a ja dam ci uprzejmość wyjaśnienia powodów. Największym powodem jest to, że nie używa Pythona (nie wieloplatformowego), więc jest uszkodzony, chyba że działa pod Windows. Po drugie, nie jest to „szybsza metoda” (chyba że szybsza oznacza szybkie i brudne-nie-przeszkadzające-czytanie-dokumentów) - przekierowywanie do innego skryptu jest notorycznie powolne.
MarkHu,
1
@MarkHu Właściwie ten skrypt narodził się z konieczności szybkiego sprawdzenia zawartości dużego folderu ze skryptu Pythona. W tym przypadku szybsza metoda oznacza, że ​​najszybciej (lub szybciej niż metoda czystego Pythona) pobiera nazwę najnowszego folderu. Zapraszam do dodania podobnego skryptu dla Linuksa, prawdopodobnie opartego na ls -Art | tail -n 1. Prosimy o ocenę wydajności rozwiązania przed zgłoszeniem reklamacji.
ic_fl2
0

Używałem tego w Pythonie 3, w tym dopasowywanie wzorców w nazwie pliku.

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
źródło