Como obter o arquivo mais recente em uma pasta usando python


126

Preciso obter o arquivo mais recente de uma pasta usando python. Enquanto estiver usando o código:

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

Estou recebendo o erro abaixo:

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


2
Qual arquivo você está tentando encontrar? adicione seu código relevante ao quesiton.
Naeem Ul Wahhab

1
Estou supondo por que pode não estar funcionando para você: "arquivos" é uma lista de elementos de nome de arquivo ou uma única string de nome de arquivo?
mpurg 5/09/16

Respostas:


321

O que for atribuído à filesvariável está incorreto. Use o seguinte 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

4
E se, em vez de um arquivo, eu quiser encontrar a última pasta criada / modificada?
Link

1
@Link, o mesmo código funciona para isso. Se você quiser verificar se é uma pasta ou não, pode verificarif os.path.isdir(latest_file):
Marlon Abeykoon

6
Esquisito. Eu tive que usar "min" para obter o arquivo mais recente. Algumas pesquisas sugeriram que é específico.
Graeck 12/12

15
Esta é uma excelente resposta - OBRIGADO! Eu gosto de trabalhar com pathlib.Pathobjetos mais do que strings e os.path. Com pathlib.Path objetos sua resposta torna-se: list_of_paths = folder_path.glob('*'); latest_path = max(list_of_paths, key=lambda p: p.stat().st_ctime)
Phil

4
@phil Você ainda pode usar os.path.getctimecomo chave, mesmo com Pathobjetos.
Berislav Lopac

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

é um código bastante incompleto. O que é files? Provavelmente é uma lista de nomes de arquivos, saindo de os.listdir().

Mas esta lista lista apenas as partes do nome do arquivo (também conhecidas como "nomes de base"), porque seu caminho é comum. Para usá-lo corretamente, você deve combiná-lo com o caminho que leva a ele (e usado para obtê-lo).

Como (não testado):

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

Estou certo de que os que recusam podem explicar o que exatamente está errado.
glglgl

3
Não sei, testado para você, parece funcionar. Além disso, você foi o único a se importar em explicar um pouco. Ler a resposta aceita me fez pensar que a coisa 'glob' era necessária, enquanto absolutamente não é. Graças
Arnaud P

4
@ David Claro, é claro. Basta inserir if basename.endswith('.csv')na lista de compreensão.
glglgl

1
@BreakBadSP Se você quer flexibilidade, está certo. Se você está restrito a um determinado diretório, não vejo como o seu pode ser mais eficiente. Mas, às vezes, a legibilidade é mais importante que a eficiência; portanto, a sua pode ser realmente melhor nesse sentido.
glglgl

1
Obrigado por isso, eu usei isso em muitas das minhas funções ETL!
Manakin

9

Eu sugeriria usar em glob.iglob()vez de glob.glob(), pois é mais eficiente.

glob.iglob () Retorna um iterador que gera os mesmos valores que glob () sem realmente armazená-los todos simultaneamente.

Que significa glob.iglob() que será mais eficiente.

Geralmente uso o código abaixo para encontrar o arquivo mais recente correspondente ao meu padrão:

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


NOTA: Existem variantes de maxfunção. No caso de encontrar o arquivo mais recente, usaremos a variante abaixo: max(iterable, *[, key, default])

que precisa ser iterável, portanto seu primeiro parâmetro deve ser iterável. No caso de encontrar o máximo de nums, podemos usar a variante beow:max (num1, num2, num3, *args[, key])


1
Eu gosto desse max()tipo. No meu caso, usei um diferente, key=os.path.basenamepois os nomes dos arquivos tinham registros de data e hora.
MarkHu

4

Tente classificar itens por hora de criação. O exemplo abaixo classifica os arquivos em uma pasta e obtém o primeiro elemento mais recente.

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

Não tenho a reputação de comentar, mas o ctime da resposta de Marlon Abeykoons não deu o resultado correto para mim. Usar o mtime faz o truque. (chave = os.path.get m tempo))

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

Encontrei duas respostas para esse problema:

python os.path.getctime max não retorna a última diferença entre python - getmtime () e getctime () no sistema unix


1

(Editado para melhorar a resposta)

Primeiro defina uma função get_latest_file

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

Você também pode usar uma 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 você usa o Python 3 , pode usar o iglob .

Código completo para retornar o nome do arquivo mais 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

De onde você conseguiu o JuniperAccessLog-standalone-FCL_VPNpapel?
glglgl

Esta falha em arquivos 0 comprimento no Windows 10.
Superdooperhero

1

Eu tentei usar as sugestões acima e meu programa travou, então eu descobri que o arquivo que estou tentando identificar foi usado e ao tentar usar 'os.path.getctime' ele travou. o que finalmente funcionou para mim foi:

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

esse código obtém o objeto incomum entre os dois conjuntos de listas de arquivos não é o mais elegante e, se vários arquivos forem criados ao mesmo tempo, provavelmente não será estável


1

Um método muito mais rápido no Windows (0.05s), chame um script bat que faça isso:

get_latest.bat

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

onde \\directory\in\questioné o diretório que você deseja 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)

se encontrar um arquivo stdouté o caminho estderr é Nenhum.

Use stdout.decode("utf-8").rstrip()para obter a representação de sequência utilizável do nome do arquivo.


Não sei por que isso está atraindo votos negativos, para aqueles que precisam executar essa tarefa rapidamente, esse é o método mais rápido que pude encontrar. E às vezes é necessário fazer isso muito rapidamente.
22418 ic_fl2 #

Tenha um voto positivo. Não estou fazendo isso no Windows, mas se você estiver procurando velocidade, as outras respostas exigirão uma iteração de todos os arquivos em um diretório. Portanto, se os comandos do shell no seu sistema operacional que especificam uma ordem de classificação dos arquivos listados estiverem disponíveis, o primeiro ou o último resultado disso deverá ser mais rápido.
Jim Hunziker

1
Obrigado, na verdade, estou mais preocupado com uma solução melhor do que essa (como em python similarmente rápido, mas puro), então esperava que alguém pudesse elaborar isso.
ic_fl2

2
Desculpe, mas eu tive que recusar o voto e darei a você a cortesia de explicar os motivos. O maior motivo é que ele não está usando python (não é multiplataforma), portanto, quebrado, a menos que seja executado no Windows. Em segundo lugar, esse não é um "método mais rápido" (a menos que mais rápido signifique documentos rápidos e sujos, que não se incomodam na leitura de documentos) - o envio para outro script é notoriamente lento.
MarkHu

1
@ MarkHu Na verdade, esse script nasceu da necessidade de verificar rapidamente o conteúdo de uma grande pasta a partir de um script python. Portanto, nesse caso, método mais rápido significa que obtém o nome do arquivo da pasta mais nova o mais rápido (ou mais rápido que um método python puro). Sinta-se à vontade para adicionar um script semelhante para o Linux, provavelmente baseado em ls -Art | tail -n 1. Avalie o desempenho de uma solução antes de fazer reivindicações sobre ela.
ic_fl2 17/01

0

Eu tenho usado isso no Python 3, incluindo correspondência de padrões no nome do arquivo.

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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.