Як отримати дату та час створення файлів та дати модифікації в Python?


932

У мене є сценарій, який повинен виконувати деякі речі, засновані на датах створення та модифікації файлів, але повинен працювати в Linux та Windows .

Який найкращий крос-платформний спосіб отримати створення та модифікацію файлів date/timesу Python ?


57
Ви не можете отримати час створення файлів міжплатформенним способом. Дивіться docs.python.org/library/os.path.html#os.path.getctime
Гліф

Відповіді:


620

Отримати якусь дату зміни крос-платформенним способом просто - просто зателефонуйте, і ви отримаєте часову позначку Unix, коли востаннє змінився файл .os.path.getmtime(path)path

З іншого боку, отримання дат створення файлів є нескінченно залежним від платформи і відрізняється навіть між трьома великими ОС:

  • У Windows файл ctime(задокументований на веб- сайті https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx ) зберігає дату його створення. Ви можете отримати доступ до цього в Python через os.path.getctime()або .st_ctimeатрибут результату дзвінка до os.stat(). Це не буде працювати в Unix, де в ctime останній раз змінювались атрибути або вміст файлу .
  • На Mac , а також деяких інших ОС на базі Unix можна використовувати .st_birthtimeатрибут результату дзвінка до os.stat().
  • В Linux це наразі неможливо, принаймні без написання розширення C для Python. Хоча деякі файлові системи, які зазвичай використовуються в Linux , зберігають дати створення (наприклад, ext4зберігають їх у st_crtime), ядро ​​Linux не пропонує способу доступу до них ; зокрема, структури, які він повертає з stat()викликів на C, станом на останню версію ядра, не містять жодних полів дати створення . Ви також можете бачити, що в st_crtimeданий час ідентифікатор не міститься ніде в джерелі Python . Принаймні , якщо ви на ext4, дані в прикріплюються до дескрипторів в файлової системі, але немає зручного способу доступу до нього.

    Наступне найкраще в Linux - це отримати доступ до файлу mtime, через os.path.getmtime()або .st_mtimeатрибут os.stat()результату. Це дасть вам востаннє змінення вмісту файлу, що може бути достатньо для деяких випадків використання.

Збираючи це все разом, крос-платформний код повинен виглядати приблизно так ...

import os
import platform

def creation_date(path_to_file):
    """
    Try to get the date that a file was created, falling back to when it was
    last modified if that isn't possible.
    See http://stackoverflow.com/a/39501288/1709587 for explanation.
    """
    if platform.system() == 'Windows':
        return os.path.getctime(path_to_file)
    else:
        stat = os.stat(path_to_file)
        try:
            return stat.st_birthtime
        except AttributeError:
            # We're probably on Linux. No easy way to get creation dates here,
            # so we'll settle for when its content was last modified.
            return stat.st_mtime

9
Я зробив усе можливе, щоб зібрати це разом (і витратив кілька годин на дослідження), і я впевнений, що це принаймні правильніше, ніж відповіді, які були тут раніше, але це справді важка тема, і я ' буду вдячний за будь-які виправлення, роз’яснення чи іншу інформацію, яку можуть запропонувати люди. Зокрема, я хотів би побудувати спосіб доступу до цих даних на ext4дисках під Linux, і я хотів би дізнатися, що відбувається, коли Linux читає файли, написані Windows, або навпаки, враховуючи, що вони використовуються по- st_ctimeрізному.
Марк Амері

25
Відверто кажучи, час створення файлів зазвичай досить марний. Коли ви відкриваєте існуючий файл для запису в режимі "w", він не замінює його, він просто відкриває існуючий файл і обрізає його. Незважаючи на те, що вміст файлу абсолютно не пов’язаний із тим, що було в ньому під час створення, вам все одно скажуть, що файл був "створений" задовго до поточної версії. І навпаки, редактори, які використовують атомну заміну при збереженні (оригінальний файл замінюється новим тимчасовим файлом незавершеного виробництва), показали б новішу дату створення, навіть якщо ви просто видалили один символ. Використовуйте час модифікації, не грабіть час створення.
ShadowRanger

3
Через багато років я нарешті знайшов собі час для створення файлів! Я пишу код, щоб перевірити конвенцію іменування файлів у певних каталогах, тому, перш за все, я хочу розглянути файли, які були вперше названі після створення конвенції. Заміна всього вмісту (mtime) не має значення: якщо він уже був там, то він вже зібрався.
Стів Джессоп

1
Привіт Марку. Я пропоную спрощення. В Linux повернення stat.st_ctimeє більш доречним, оскільки, у багатьох випадках, час останньої зміни метаданих може бути часом створення (принаймні ctime, ближче до реального часу створення, ніж mtime). Тому ви можете просто замінити фрагмент на stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime. Як ти гадаєш? Ура
олібре

4
@olibre "принаймні ctime ближче до реального часу створення, ніж mtime" - ні, це не так; це щось я бачив кілька разів, але це абсолютно помилково. Якщо ви не вручну переплуталися зі значеннями в вашому иноді ctimeзавжди повинна бути дорівнює або пізніше , ніж mtime, тому що mtimeзміна призводить до ctimeзміни (оскільки mtimeсам вважається «метаданих»). Дивіться stackoverflow.com/a/39521489/1709587, де я навожу приклад коду для ілюстрації цього.
Марк Амері

676

У вас є пара варіантів. Для одного ви можете скористатися функціями os.path.getmtimeта os.path.getctime:

import os.path, time
print("last modified: %s" % time.ctime(os.path.getmtime(file)))
print("created: %s" % time.ctime(os.path.getctime(file)))

Ваш інший варіант - використовувати os.stat:

import os, time
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(file)
print("last modified: %s" % time.ctime(mtime))

Примітка : ctime()це НЕ відноситься до часу створення на * NIX систем, а останній раз , коли дані індексних дескрипторів змінилися. (спасибі kiro, який зробив цей факт більш зрозумілим у коментарях, надавши посилання на цікавий пост у блозі)


169
На всякий випадок, якщо хтось пропустить коментар @ Glyph до цього питання, ctime не означає час створення в системах POSIX . Цікаво, скільки людей за останні три роки обійняли цю посаду і продовжували писати баггі-код.
kojiro

16
Пам’ятайте, що перший приклад дає рядок, а не дату чи номер.
gak

1
@kojiro повідомлення в блозі ви пов'язані з може бути більш явним , що на Unix до файлу ctimeоновлюється кожного разу , коли mtimeробить (так як mtimeце «метадані»), і тому , ctimeяк правило , завжди дорівнює або більше , ніжmtime . Таким чином, трактувати ctimeяк "створений" час взагалі не має сенсу. -1!
Марк Амері

Ваш перший варіант повертає однакові результати як для створення файлів, так і для останньої модифікації! Last modified: Fri Jan 31 11:08:13 2020і Created: Fri Jan 31 11:08:13 2020на Linux Ubuntu 16.04!
Färid Alijani

Я виявляю, що time.ctime(os.path.getmtime(file))повертає 2 типи рядків, залежно від того, чи файл був змінений системою або користувачем. Якщо вона була змінена системою, рядок буде мати два проміжки між місяцем і днем. Я не знаю чому
Маттео Антоліні

376

Найкраща функція, яка використовується для цього, - os.path.getmtime () . Всередині це просто використовуєтьсяos.stat(filename).st_mtime .

Модуль datetime - це найкраща маніпуляція часових позначок, тому ви можете отримати дату модифікації як такий datetimeоб'єкт:

import os
import datetime
def modification_date(filename):
    t = os.path.getmtime(filename)
    return datetime.datetime.fromtimestamp(t)

Приклад використання:

>>> d = modification_date('/var/log/syslog')
>>> print d
2009-10-06 10:50:01
>>> print repr(d)
datetime.datetime(2009, 10, 6, 10, 50, 1)

1
Ця відповідь також трохи неправильна. getmtime- це найближча річ, доступна в Unix (де дати створення не представляється можливим), але, безумовно, не найкраща функція для використання в Windows, де час ctimeстворення.
Марк Амері

3
@MarkAmery - Ця відповідь чітко позначена як саме про час модифікації.
ArtOfWarfare

47

os.stat https://docs.python.org/2/library/stat.html#module-stat

редагувати: У новій версії ви, ймовірно, повинні використовувати os.path.getmtime () (дякую Крістіану Оудару),
але зауважте, що воно повертає значення з плаваючою комою time_t з дрібними секундами (якщо ваша ОС підтримує це)


44
os.path.getmtime () робиться для цього і простіше.
Крістіан Оудард

5
Пункт "у новішому коді" тут трохи не вводить в оману. os.path.getmtime()існує вже з моменту Python 1.5.2 (див. старі документи ), випущений до того, як я втратив більшість своїх дитячих зубів і майже за десять років до того, як ви написали оригінальну версію цієї відповіді.
Марк Амері

39

Існує два способи отримання модного часу, os.path.getmtime () або os.stat (), але ctime не є надійною кросплатформою (див. Нижче).

os.path.getmtime ()

getmtime ( шлях )
Повертає час останньої модифікації шляху. Повернене значення - це число, що дає кількість секунд після епохи (див. Модуль часу). Підніміть os.error, якщо файл не існує або недоступний. Нове у версії 1.5.2. Змінено у версії 2.3: Якщо os.stat_float_times () повертає значення True, результатом стає число з плаваючою комою.

os.stat ()

stat ( шлях )
Виконайте системний виклик stat () на заданому шляху. Повернене значення - це об'єкт, атрибути якого відповідають членам структури stat, а саме: st_mode (біти захисту), st_ino (номер введення), st_dev (пристрій), st_nlink (кількість жорстких посилань), st_uid (ідентифікатор користувача власника ), st_gid (ідентифікатор групи власника), st_size (розмір файлу, в байтах), st_atime (час останнього доступу), st_mtime (час останньої модифікації вмісту), st_ctime (залежно від платформи; час останньої зміни метаданих) в Unix або час створення в Windows) :

>>> import os
>>> statinfo = os.stat('somefile.txt')
>>> statinfo
(33188, 422511L, 769L, 1, 1032, 100, 926L, 1105022698,1105022732, 1105022732)
>>> statinfo.st_size
926L
>>> 

У наведеному вище прикладі ви використовуєте statinfo.st_mtime або statinfo.st_ctime, щоб отримати mtime та ctime відповідно.


13

У Python 3.4 і вище ви можете використовувати об'єктно-орієнтований інтерфейс модуля pathlib, який включає обгортки для більшої частини модуля os. Ось приклад отримання статистики файлів.

>>> import pathlib
>>> fname = pathlib.Path('test.py')
>>> assert fname.exists(), f'No such file: {fname}'  # check that the file exists
>>> print(fname.stat())
os.stat_result(st_mode=33206, st_ino=5066549581564298, st_dev=573948050, st_nlink=1, st_uid=0, st_gid=0, st_size=413, st_atime=1523480272, st_mtime=1539787740, st_ctime=1523480272)

Для отримання додаткової інформації про те, що os.stat_resultмістить, див . Документацію . За потрібний час модифікації fname.stat().st_mtime:

>>> import datetime
>>> mtime = datetime.datetime.fromtimestamp(fname.stat().st_mtime)
>>> print(mtime)
datetime.datetime(2018, 10, 17, 10, 49, 0, 249980)

Якщо ви хочете, щоб час створення в Windows або остання зміна метаданих в Unix, ви використовуєте fname.stat().st_ctime:

>>> ctime = datetime.datetime.fromtimestamp(fname.stat().st_ctime)
>>> print(ctime)
datetime.datetime(2018, 4, 11, 16, 57, 52, 151953)

У цій статті є корисніша інформація та приклади для модуля pathlib.


11

os.statповертає названий кортеж з st_mtimeта st_ctimeатрибутами. Час модифікації є st_mtimeна обох платформах; на жаль, для Windows ctimeозначає "час створення", тоді як для POSIX це означає "змінити час". Я не знаю жодного способу отримати час створення на платформах POSIX.


Ось докладніше про теги-кортежі: stackoverflow.com/questions/2970608/… Вони працюють як кортежі, але спробуйте dir(..)один. Напр.dir(os.stat(os.listdir('.')[0]))
Євгеній Сергєєв

9
import os, time, datetime

file = "somefile.txt"
print(file)

print("Modified")
print(os.stat(file)[-2])
print(os.stat(file).st_mtime)
print(os.path.getmtime(file))

print()

print("Created")
print(os.stat(file)[-1])
print(os.stat(file).st_ctime)
print(os.path.getctime(file))

print()

modified = os.path.getmtime(file)
print("Date modified: "+time.ctime(modified))
print("Date modified:",datetime.datetime.fromtimestamp(modified))
year,month,day,hour,minute,second=time.localtime(modified)[:-3]
print("Date modified: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

print()

created = os.path.getctime(file)
print("Date created: "+time.ctime(created))
print("Date created:",datetime.datetime.fromtimestamp(created))
year,month,day,hour,minute,second=time.localtime(created)[:-3]
print("Date created: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

відбитки

somefile.txt
Modified
1429613446
1429613446.0
1429613446.0

Created
1517491049
1517491049.28306
1517491049.28306

Date modified: Tue Apr 21 11:50:46 2015
Date modified: 2015-04-21 11:50:46
Date modified: 21/04/2015 11:50:46

Date created: Thu Feb  1 13:17:29 2018
Date created: 2018-02-01 13:17:29.283060
Date created: 01/02/2018 13:17:29

-1: Так само, як і інші відповіді, це не дасть вам часу створення файлу в Windows (що, знову ж таки, у відповіді навіть не згадується).
ntninja

@ntninja Ви впевнені в цьому? Я використовую тільки Windows, і це абсолютно працює. Я написав цей сценарій на початку 2015 року. Я вважаю, що він був більш чітким, прямо до суті, повним і зрозумілим, ніж інші. (що я випадково вирішив шукати тут замість старих сценаріїв, лише якщо вийшло щось нове. ні ... це так)
калюжа

О, я хотів сказати "... це не дасть вам часу створення файлу, якщо ви не перебуваєте в Windows". Вибачте! Залишається фактом, що ця відповідь не є портативною і не згадує цей факт. (Приклад виведення в Linux: pastebin.com/50r5vGBE )
ntninja

@ntninja ти підеш сказати всім іншим тоді?
Калюжа

Тут уже залишилися деякі коментарі, і я незабаром опублікую відповідь, яка працює і на (недавньому) Linux. Але насправді, єдине, що не так у вашому дописі, це те, що це лише відповідь на Windows, яка не згадує цей факт. У запитанні OP навіть спеціально попросили рішення, сумісне з Windows та Linux. Як такий, я думаю, було б дуже корисно, якби ви додали цю «деталь» десь у верхній частині, щоб люди не вводили в оману думки про час, що вони шукають, орієнтуючись на кілька платформ.
ntninja

2
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>> 

-1: Як було зазначено в іншому місці, це не дасть вам часу створення файлу, якщо ви не знаходитесь у Windows (про що відповідь навіть не згадується!).
ntninja

0

Якщо наступні символьні посилання не важливі, ви також можете використовувати os.lstatвбудований.

>>> os.lstat("2048.py")
posix.stat_result(st_mode=33188, st_ino=4172202, st_dev=16777218L, st_nlink=1, st_uid=501, st_gid=20, st_size=2078, st_atime=1423378041, st_mtime=1423377552, st_ctime=1423377553)
>>> os.lstat("2048.py").st_atime
1423378041.0

Це дасть час останнього читання (принаймні, на Unix), що точно не те, про що просили.
Марк Амері

0

Можливо, варто поглянути на crtimeбібліотеку, яка реалізує міжплатформний доступ до часу створення файлів.

from crtime import get_crtimes_in_dir

for fname, date in get_crtimes_in_dir(".", raise_on_error=True, as_epoch=False):
    print(fname, date)
    # file_a.py Mon Mar 18 20:51:18 CET 2019

1
Я настійно раджу проти цього: він використовує debugfsв Linux, який за визначенням нестабільний, вимагає кореневого доступу верхнього рівня для всього, і майже кожен аспект, як правило, є однією з речей, про які ваша мама завжди попереджала. (Але так, це, мабуть, спрацює, якщо ви справді відчайдушно і справді станете справжнім суперпользователем в системі без безпечного завантаження…)
ntninja

@ntninja я б ніколи не використовував у виробництві, але це може бути корисно для "домашнього сценарію".
Дельган

-2

os.statвключає час створення. Просто немає визначення st_anything для елемента, os.stat()який містить час.

Тому спробуйте це:

os.stat('feedparser.py')[8]

Порівняйте це з датою створення файлу у ls -lah

Вони повинні бути однаковими.


6
Неправильно! os.stat ('feedparser.py') [8] посилається на st_mtime, а не на час створення. Зверніться до документації: docs.python.org/library/os.html#os.stat
millerdev

4
Будь ласка, використовуйте .st_ctime замість некрасивих чисел [8].
guettli

-3

Мені вдалося отримати час створення posix, запустивши команду stat системи та проаналізувавши вихід.

commands.getoutput('stat FILENAME').split('\"')[7]

Запуск статистики за межами python від Terminal (OS X) повернув:

805306374 3382786932 -rwx------ 1 km staff 0 1098083 "Aug 29 12:02:05 2013" "Aug 29 12:02:05 2013" "Aug 29 12:02:20 2013" "Aug 27 12:35:28 2013" 61440 2150 0 testfile.txt

... де четвертим датою є створення файлу (а не час зміни часу, як зазначали інші коментарі).


13
-1: Розбір результатів, призначених для людей з команди оболонки, дуже погана ідея. І ця команда навіть не є сумісною.
MestreLion
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.