Как получить последний файл в папке с помощью Python

127

Мне нужно получить последний файл папки с помощью python. При использовании кода:

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

Я получаю следующую ошибку:

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

garlapak
источник
2
Какой файл вы пытаетесь найти? добавьте соответствующий код в вопрос.
Наим Уль Ваххаб,
1
Я догадываюсь, почему это может не сработать для вас: «файлы» - это список элементов имени файла или одна строка имени файла?
mpurg

Ответы:

324

Все, что присвоено filesпеременной, неверно. Используйте следующий код.

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
Что делать, если вместо файла я хочу найти последнюю созданную / измененную папку?
Ссылка
1
@Link для этого работает тот же код. Если вы хотите проверить свою папку или нет, вы можете проверитьif os.path.isdir(latest_file):
Марлон
6
Weird. Мне пришлось использовать «min», чтобы получить последний файл. Некоторые поиски намекнули, что это специфично для ОС.
Грек
15
Отличный ответ - СПАСИБО! Мне нравится работать с pathlib.Pathобъектами больше, чем со строками и os.path. С объектами pathlib.Path ваш ответ будет следующим: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Фил
4
@phil Вы все еще можете использовать os.path.getctimeкак ключ, даже с Pathобъектами.
Берислав Лопац
42
max(files, key = os.path.getctime)

довольно неполный код. Что есть files? Вероятно, это список имен файлов, выходящих из os.listdir().

Но в этом списке перечислены только части имен файлов (также известные как «базовые имена»), поскольку их путь является общим. Чтобы использовать его правильно, вы должны объединить его с путем, ведущим к нему (и использованным для его получения).

Такие как (непроверенные):

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
источник
Я уверен, что те, кто проголосовал против, могут объяснить, что именно не так.
glglgl 06
3
Не знаю, проверено для вас, похоже, работает. Вдобавок ко всему, вы были единственной, кто захотел немного объяснить. Прочитав принятый ответ, я подумал, что вещь 'glob' нужна, а это абсолютно не так. Спасибо
Arnaud P
4
@ Дэвид Конечно. Просто вставьте if basename.endswith('.csv')в список понимание.
glglgl
1
@BreakBadSP Если вам нужна гибкость, вы правы. Если вы ограничены определенным каталогом, я не понимаю, как ваш может быть более эффективным. Но иногда удобочитаемость важнее эффективности, так что в этом смысле у вас действительно может быть лучше.
glglgl 08
1
Спасибо за это, я использовал это во многих своих функциях ETL!
Manakin
9

Я бы предложил использовать glob.iglob()вместо glob.glob(), так как это более эффективно.

glob.iglob () Возвращает итератор, который дает те же значения, что и glob (), без фактического сохранения их всех одновременно.

Что значит glob.iglob()будет эффективнее.

Я в основном использую приведенный ниже код, чтобы найти последний файл, соответствующий моему шаблону:

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


ПРИМЕЧАНИЕ: Существуют варианты maxфункций, в случае нахождения последнего файла мы будем использовать следующий вариант: max(iterable, *[, key, default])

который требует итерации, поэтому ваш первый параметр должен быть итерируемым. В случае нахождения максимального числа мы можем использовать следующий вариант:max (num1, num2, num3, *args[, key])

BreakBadSP
источник
1
Мне нравится этот max()сорт. В моем случае я использовал другое, key=os.path.basenameпоскольку в именах файлов были временные метки.
MarkHu
4

Попробуйте отсортировать предметы по времени создания. Пример ниже сортирует файлы в папке и получает первый элемент, который является последним.

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
источник
4

У меня нет репутации, чтобы комментировать, но ответ Марлона Абейкуна не дал мне правильного результата. Однако использование mtime помогает. (ключ = os.path.get m время))

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

Я нашел два ответа на эту проблему:

python os.path.getctime max не возвращает последнюю разницу между python - getmtime () и getctime () в системе unix

CRLF
источник
1

(Отредактировано для улучшения ответа)

Сначала определите функцию get_latest_file

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

Вы также можете использовать строку документации!

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)

Если вы используете Python 3 , вы можете использовать вместо этого iglob .

Полный код для возврата имени последнего файла:

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
Наим Уль Ваххаб
источник
Откуда вы взяли JuniperAccessLog-standalone-FCL_VPNроль?
glglgl 05
Это не работает с файлами
нулевой
1

Я попытался использовать приведенные выше предложения, и моя программа разбилась, чем я понял, что файл, который я пытаюсь идентифицировать, был использован, и при попытке использовать os.path.getctime он разбился. что, наконец, сработало для меня:

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

этот код получает необычный объект между двумя наборами списков файлов, он не самый элегантный, и если одновременно создается несколько файлов, он, вероятно, не будет стабильным

AlexFink
источник
1

Гораздо более быстрый метод в Windows (0,05 с), вызовите сценарий летучей мыши, который делает это:

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\questionнаходится каталог, который вы хотите исследовать.

get_latest.py

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

если он находит файл, stdoutэто путь иstderr None.

Используется stdout.decode("utf-8").rstrip()для получения удобного строкового представления имени файла.

ic_fl2
источник
Не уверен, почему это приводит к снижению голосов, для тех, кому нужно быстро выполнить эту задачу, это самый быстрый метод, который я мог найти. И иногда это нужно делать очень быстро.
ic_fl2 01
Проголосуйте. Я не делаю этого в Windows, но если вы ищете скорость, другие ответы требуют итерации всех файлов в каталоге. Поэтому, если доступны команды оболочки в вашей ОС, которые определяют порядок сортировки перечисленных файлов, получение первого или последнего результата должно быть быстрее.
Джим Ханзикер
1
Спасибо. На самом деле меня больше беспокоит лучшее решение, чем это (как в таком же быстром, но чистом питоне), поэтому я надеялся, что кто-то сможет уточнить это.
ic_fl2
2
Извините, но мне пришлось проголосовать против, и я любезно объясню вам причины. Самая большая причина в том, что он не использует python (не кроссплатформенный), поэтому он не работает, если он не работает под Windows. Во-вторых, это не «более быстрый метод» (если только «быстрее» не означает «быстро-грязно-не-беспокоиться-читать-документы») - переход к другому сценарию заведомо медленный.
MarkHu
1
@MarkHu На самом деле этот скрипт родился из-за необходимости быстро проверять содержимое большой папки с помощью скрипта Python. Таким образом, в этом случае более быстрый метод означает, что быстрее всего получает имя файла самой новой папки (или быстрее, чем чистый метод python). Не стесняйтесь добавить аналогичный скрипт для linux, возможно, на основе ls -Art | tail -n 1. Пожалуйста, оцените производительность решения, прежде чем заявлять о нем.
ic_fl2
0

Я использовал это в Python 3, включая сопоставление с образцом в имени файла.

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)
Джейми Булл
источник