У меня есть скрипт, который должен делать некоторые вещи, основанные на датах создания и изменения файлов, но должен работать в Linux и Windows .
Какой лучший кроссплатформенный способ получить создание и изменение файлов date/times
в Python ?
У меня есть скрипт, который должен делать некоторые вещи, основанные на датах создания и изменения файлов, но должен работать в Linux и Windows .
Какой лучший кроссплатформенный способ получить создание и изменение файлов date/times
в Python ?
Ответы:
Получить какую-то дату модификации кроссплатформенным способом легко - просто позвоните, и вы получите метку времени Unix, когда файл был последний раз изменен.os.path.getmtime(path)
path
Получение дат создания файла , с другой стороны, зависит от платформы и зависит даже от трех больших ОС:
ctime
(задокументированный по адресу https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx ) хранит дату его создания. Вы можете получить доступ к этому в Python через os.path.getctime()
или к .st_ctime
атрибуту результата вызова os.stat()
. Это не будет работать в Unix, где в ctime
последний раз менялись атрибуты или содержимое файла ..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
ext4
дисках под Linux, и я хотел бы узнать, что происходит, когда Linux читает файлы, написанные Windows, или наоборот, учитывая, что они используют по- st_ctime
разному.
"w"
, он не заменяет его, он просто открывает существующий файл и усекает его. Даже если содержимое файла совершенно не связано с тем, что оно имело при создании, вам все равно сказали бы, что файл «создан» задолго до текущей версии. И наоборот, редакторы, использующие атомарную замену при сохранении (исходный файл заменяется новым временным файлом, находящимся в процессе выполнения), будут отображать более позднюю дату создания, даже если вы только что удалили один символ. Используйте время модификации, а не время для создания.
stat.st_ctime
более уместен, поскольку во многих случаях время последнего изменения метаданных может быть временем создания (по крайней мере ctime
, ближе к реальному времени создания, чем mtime
). Поэтому вы можете просто заменить свой фрагмент на stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime
. Что вы думаете? Приветствия
ctime
всегда должна быть равна или позже , чем mtime
, потому что mtime
изменение приводит к ctime
изменению (поскольку mtime
сам считается «метаданных»). См. Stackoverflow.com/a/39521489/1709587, где я приведу пример кода, чтобы проиллюстрировать это.
У вас есть несколько вариантов. С одной стороны , вы можете использовать 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 систем, а последний раз , когда данные индексных дескрипторов изменились. (спасибо Кодзиро за разъяснение этого факта в комментариях, предоставив ссылку на интересную запись в блоге)
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 пробела между месяцем и днем. Я не знаю почему
Лучшая функция для этого - 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)
getmtime
это самая близкая вещь, доступная в Unix (где получение дат создания невозможно), но это определенно не лучшая функция для использования в Windows, где время ctime
создания.
os.stat https://docs.python.org/2/library/stat.html#module-stat
edit: в более новом коде вы, вероятно, должны использовать os.path.getmtime () (спасибо Christian Oudard),
но обратите внимание, что он возвращает значение с плавающей запятой time_t с долями секунды (если ваша ОС поддерживает это)
os.path.getmtime()
существует с Python 1.5.2 (см. старые документы ), выпущенного до того, как я потерял большую часть своих молочных зубов, и почти за десять лет до того, как вы написали оригинальную версию этого ответа.
Есть два метода для получения времени мода, os.path.getmtime () или os.stat (), но ctime не является надежной кроссплатформенной (см. Ниже).
getmtime ( path )
Возвращает время последней модификации пути. Возвращаемое значение - это число, указывающее количество секунд с начала эпохи (см. Модуль времени). Поднимите os.error, если файл не существует или недоступен. Новое в версии 1.5.2. Изменено в версии 2.3: если os.stat_float_times () возвращает True, результатом является число с плавающей запятой.
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 соответственно.
В 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.
os.stat
возвращает именованный кортеж st_mtime
и st_ctime
атрибуты. Время модификации st_mtime
на обеих платформах; к сожалению, в Windows это ctime
означает «время создания», а в POSIX - «время изменения». Я не знаю ни одного способа получить время создания на платформах POSIX.
dir(..)
один. Напримерdir(os.stat(os.listdir('.')[0]))
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
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>>
Если следующие символические ссылки не важны, вы также можете использовать 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
Возможно, стоит взглянуть на 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
debugfs
Linux, который по определению нестабилен, требует корневого доступа на высшем уровне для всего и почти во всех аспектах - одна из тех вещей, о которых ваша мама всегда предупреждала. (Но да, это, вероятно, работает, если вы действительно отчаялись и оказались настоящим суперпользователем в системе без безопасной загрузки…)
os.stat
действительно включает время создания. Просто нет определения st_anything для элемента, os.stat()
который содержит время.
Итак, попробуйте это:
os.stat('feedparser.py')[8]
Сравните это с датой создания файла в ls -lah.
Они должны быть одинаковыми.
Я смог получить время создания в 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, как отмечалось в других комментариях).