Как узнать дату и время создания и изменения файла в Python?


935

У меня есть скрипт, который должен делать некоторые вещи, основанные на датах создания и изменения файлов, но должен работать в Linux и Windows .

Какой лучший кроссплатформенный способ получить создание и изменение файлов date/timesв Python ?


57
Вы не можете получить время создания файла кросс-платформенным способом. См. Docs.python.org/library/os.path.html#os.path.getctime
Glyph

Ответы:


622

Получить какую-то дату модификации кроссплатформенным способом легко - просто позвоните, и вы получите метку времени 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) не имеет значения: если он уже был там, значит, он в нем работает.
Steve Jessop

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

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 систем, а последний раз , когда данные индексных дескрипторов изменились. (спасибо Кодзиро за разъяснение этого факта в комментариях, предоставив ссылку на интересную запись в блоге)


169
На всякий случай, если кто-то пропустит комментарий @ Glyph к этому вопросу, ctime не означает время создания в системах POSIX . Интересно, сколько людей просмотрели этот пост за последние три года и начали писать глючный код.
Кодзиро

16
Имейте в виду, что первый пример дает вам строку, а не дату или время.
Гак

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!
Ферид Алиджани

Я обнаружил, что time.ctime(os.path.getmtime(file))возвращает 2 типа строк, в зависимости от того, был ли файл изменен системой или пользователем. Если она была изменена системой, строка будет иметь 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

edit: в более новом коде вы, вероятно, должны использовать os.path.getmtime () (спасибо Christian Oudard),
но обратите внимание, что он возвращает значение с плавающей запятой 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 ( path )
Возвращает время последней модификации пути. Возвращаемое значение - это число, указывающее количество секунд с начала эпохи (см. Модуль времени). Поднимите os.error, если файл не существует или недоступен. Новое в версии 1.5.2. Изменено в версии 2.3: если os.stat_float_times () возвращает True, результатом является число с плавающей запятой.

os.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. Поэтому я думаю, что было бы очень полезно, если бы вы добавили эту «деталь» где-то вверху, чтобы люди не вводили в заблуждение, думая, что ctime - это то, что они ищут, ориентируясь на несколько платформ.
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
Я настоятельно рекомендую это сделать: он использует debugfsLinux, который по определению нестабилен, требует корневого доступа на высшем уровне для всего и почти во всех аспектах - одна из тех вещей, о которых ваша мама всегда предупреждала. (Но да, это, вероятно, работает, если вы действительно отчаялись и оказались настоящим суперпользователем в системе без безопасной загрузки…)
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].
Геттли

-3

Я смог получить время создания в posix, запустив системную команду stat и проанализировав вывод.

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

Запуск stat вне python из терминала (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

... где четвертой датой является время создания файла (а не время изменения ctime, как отмечалось в других комментариях).


13
-1: анализ выходных данных, предназначенных для людей, по команде оболочки - очень плохая идея. И эта команда даже не является кросс-совместимой.
МестреЛион
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.