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