Jak uzyskać datę / godzinę utworzenia i modyfikacji pliku w Pythonie?

932

Mam skrypt, który musi wykonać pewne czynności w oparciu o daty utworzenia i modyfikacji pliku, ale musi działać w systemach Linux i Windows .

Jaki jest najlepszy międzyplatformowy sposób na tworzenie i modyfikowanie plików date/timesw Pythonie ?

Mark Biek
źródło
57
Nie można uzyskać czasu tworzenia pliku na wiele platform. Zobacz docs.python.org/library/os.path.html#os.path.getctime
Glyph

Odpowiedzi:

620

Uzyskiwanie jakiejś daty modyfikacji na wiele platform jest łatwe - wystarczy zadzwonić, a otrzymasz uniksowy znacznik czasu, kiedy plik był ostatnio modyfikowany.os.path.getmtime(path)path

Z drugiej strony, uzyskiwanie dat utworzenia plików jest skomplikowane i zależne od platformy, różni się nawet między trzema dużymi systemami operacyjnymi:

Podsumowując, kod dla wielu platform powinien wyglądać mniej więcej tak ...

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
Mark Amery
źródło
9
Zrobiłem co w mojej mocy, aby zebrać to w całość (i spędziłem kilka godzin na badaniu procesu) i jestem pewien, że jest to co najmniej bardziej poprawne niż odpowiedzi, które tu były wcześniej, ale to jest naprawdę trudny temat i „ d doceniamy wszelkie poprawki, wyjaśnienia lub inne informacje, które ludzie mogą zaoferować. W szczególności chciałbym skonstruować sposób dostępu do tych danych na ext4dyskach pod Linuksem i chciałbym dowiedzieć się, co się dzieje, gdy Linux odczytuje pliki napisane przez Windows lub odwrotnie, biorąc pod uwagę, że używają one st_ctimeinaczej.
Mark Amery
25
Szczerze mówiąc, czas tworzenia pliku jest zwykle dość bezużyteczny. Kiedy otwierasz istniejący plik do zapisu w trybie "w", nie zastępuje go, po prostu otwiera istniejący plik i obcina go. Mimo że zawartość pliku jest całkowicie niezwiązana z tym, co miał podczas tworzenia, nadal można powiedzieć, że plik został „utworzony” na długo przed bieżącą wersją. I na odwrót, redaktorzy używający zamiany atomowej podczas zapisywania (oryginalny plik jest zastępowany nowym plikiem tymczasowym w toku) wyświetlałby późniejszą datę utworzenia, nawet jeśli usunąłeś tylko jeden znak. Użyj czasu modyfikacji, nie puszczaj gruba na czas tworzenia.
ShadowRanger
3
Po wielu latach wreszcie znalazłem zastosowanie do tworzenia plików! Piszę kod, aby sprawdzić konwencję nazewnictwa plików w niektórych katalogach, więc przede wszystkim chcę rozważyć pliki, które zostały nazwane po utworzeniu konwencji. Zastąpienie całej zawartości (mtime) nie ma znaczenia: jeśli już tam była, to jest dziadek.
Steve Jessop
1
Cześć Mark. Proponuję uproszczenie. W systemie Linux zwracanie stat.st_ctimejest bardziej istotne, ponieważ w wielu przypadkach czasem ostatniej zmiany metadanych może być czas utworzenia (przynajmniej ctimebliższy rzeczywistemu czasowi tworzenia niż mtime). Dlatego możesz po prostu zastąpić swój fragment stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime. Co myślisz? Pozdrawiam
olibre,
4
@olibre „przynajmniej ctime jest bliższy rzeczywistemu czasowi tworzenia niż mtime” - nie, nie jest; to stwierdziłem kilka razy, ale jest to całkowicie nieprawda. Chyba że ręcznie pomieszane z wartościami w swojej węzła, ctimezawsze powinien być równy lub później niż mtime, ponieważ mtimezmiana powoduje to ctimezmianę (bo mtimesam jest uważany za „metadane”). Zobacz stackoverflow.com/a/39521489/1709587, gdzie podam przykładowy kod ilustrujący to.
Mark Amery
676

Masz kilka możliwości. Po pierwsze możesz użyć funkcji os.path.getmtimei 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)))

Inną opcją jest użycie 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))

Uwaga : ctime()nie nie odnoszą się do czasu utworzenia na systemów uniksowych, ale raczej ostatni raz dane iwęzłów zmieniło. (podziękowania dla kojiro za wyjaśnienie tego faktu w komentarzach poprzez podanie linku do interesującego posta na blogu)

Bryan Oakley
źródło
169
Na wypadek, gdyby ktoś pominął komentarz @ Glypha do pytania, ctime nie oznacza czasu tworzenia w systemach POSIX . Zastanawiam się, ile osób przeszukało ten post w ciągu ostatnich trzech lat i napisało błędny kod.
kojiro,
16
Pamiętaj, że pierwszy przykład podaje ciąg znaków, a nie datę / godzinę lub liczbę.
gak
1
@kojiro blogu już związana może być bardziej wyraźne, że na Unix plik użytkownika ctimezostanie zaktualizowany, gdy mtimerobi (ponieważ mtimejest „metadane”), a więc ctimejest zwykle zawsze równa lub przedmtime . Traktowanie ctimejak czas „stworzony” nie ma zatem żadnego sensu. -1!
Mark Amery
Twoja pierwsza opcja zwraca te same wyniki zarówno dla utworzenia pliku, jak i ostatniej modyfikacji! Last modified: Fri Jan 31 11:08:13 2020i Created: Fri Jan 31 11:08:13 2020na Linux Ubuntu 16.04!
Färid Alijani
Odkryłem, że time.ctime(os.path.getmtime(file))zwraca 2 typy ciągów, w zależności od tego, czy plik został zmodyfikowany przez system, czy przez użytkownika. Jeśli został zmodyfikowany przez system, łańcuch będzie zawierał 2 spacje między miesiącem a dniem. Nie wiem dlaczego
Matteo Antolini
376

Najlepszą funkcją do tego celu jest os.path.getmtime () . To po prostu wykorzystuje os.stat(filename).st_mtime.

Moduł datetime jest najlepszym manipulowaniem znacznikami czasu, więc datę modyfikacji można uzyskać jako datetimeobiekt taki jak ten:

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

Przykład użycia:

>>> 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)
Christian Oudard
źródło
1
Ta odpowiedź jest również trochę błędna. getmtimejest najbliższą rzeczą dostępną w systemie Unix (gdzie uzyskanie dat utworzenia nie jest możliwe), ale zdecydowanie nie jest najlepszą funkcją do użycia w systemie Windows, gdzie ctimejest czas utworzenia.
Mark Amery
3
@MarkAmery - Ta odpowiedź jest wyraźnie oznaczona jako dotycząca czasu modyfikacji.
ArtOfWarfare
47

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

edit: W nowszym kodzie powinieneś prawdopodobnie użyć os.path.getmtime () (dzięki Christian Oudard),
ale zwróć uwagę, że zwraca zmiennoprzecinkową wartość time_t z ułamkiem sekund (jeśli twój system to obsługuje)

Martin Beckett
źródło
44
Os.path.getmtime () jest stworzony do tego i jest prostszy.
Christian Oudard
5
Klauzula „w nowym kodzie” tutaj jest nieco myląca. os.path.getmtime()istnieje od czasu wydania Python 1.5.2 (patrz stare dokumenty ), wydanego zanim straciłem większość zębów mlecznych i prawie dekadę przed napisaniem oryginalnej wersji tej odpowiedzi.
Mark Amery
39

Istnieją dwie metody uzyskania czasu mod, os.path.getmtime () lub os.stat (), ale ctime nie jest wiarygodny na różnych platformach (patrz poniżej).

os.path.getmtime ()

getmtime ( ścieżka )
Zwraca czas ostatniej modyfikacji ścieżki. Wartość zwracana to liczba podająca liczbę sekund od epoki (patrz moduł czasu). Podnieś os.error, jeśli plik nie istnieje lub jest niedostępny. Nowości w wersji 1.5.2. Zmieniono w wersji 2.3: Jeśli os.stat_float_times () zwraca True, wynikiem jest liczba zmiennoprzecinkowa.

os.stat ()

stat ( ścieżka )
Wykonaj wywołanie systemowe stat () na podanej ścieżce. Zwracana wartość to obiekt, którego atrybuty odpowiadają elementom struktury statystyki, a mianowicie: st_mode (bity ochronne), st_ino (numer i-węzła), st_dev (urządzenie), st_nlink (liczba twardych dowiązań), st_uid (identyfikator użytkownika właściciela ), st_gid (identyfikator grupy właściciela), st_size (rozmiar pliku, w bajtach), st_atime (czas ostatniego dostępu), st_mtime (czas ostatniej modyfikacji treści), st_ctime (zależny od platformy; czas ostatniej zmiany metadanych w systemie Unix lub czas utworzenia w systemie Windows) :

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

W powyższym przykładzie użyjesz statinfo.st_mtime lub statinfo.st_ctime, aby uzyskać odpowiednio mtime i ctime.

Sójka
źródło
13

W Pythonie 3.4 i nowszych można użyć zorientowanego obiektowo interfejsu modułu pathlib , który zawiera opakowania dla większości modułów systemu operacyjnego . Oto przykład pobierania statystyk plików.

>>> 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)

Aby uzyskać więcej informacji o tym os.stat_result, co zawiera, zapoznaj się z dokumentacją . Dla potrzebnego czasu modyfikacji 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)

Jeśli chcesz czas utworzenia w systemie Windows lub najnowszą zmianę metadanych w systemie Unix, możesz użyć fname.stat().st_ctime:

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

Ten artykuł zawiera bardziej pomocne informacje i przykłady dotyczące modułu pathlib.

Steven C. Howell
źródło
11

os.statzwraca nazwaną krotkę z atrybutami st_mtimei st_ctime. Czas modyfikacji jest st_mtimena obu platformach; niestety w systemie Windows ctimeoznacza „czas utworzenia”, podczas gdy w systemie POSIX oznacza „czas zmiany”. Nie znam żadnego sposobu na uzyskanie czasu tworzenia na platformach POSIX.

mithrandi
źródło
Oto więcej o tagowanych krotkach: stackoverflow.com/questions/2970608/... Działają jak krotki, ale spróbuj dir(..)jednego. Np.dir(os.stat(os.listdir('.')[0]))
Jewgienij Siergiejew
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))

odciski

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
Kałuża
źródło
-1: Podobnie jak w przypadku innych odpowiedzi, nie da ci to czasu utworzenia pliku w systemie Windows (który ponownie nie jest nawet wspomniany w odpowiedzi).
ntninja
@ntninja jesteś tego pewien? Używam tylko systemu Windows i to absolutnie działa. napisałem ten skrypt na początku 2015 roku. Uważam, że był on bardziej przejrzysty, od razu do rzeczy, kompletny i zrozumiały dla innych tutaj. (które przypadkiem postanowiłem poszukać tutaj zamiast moich starych skryptów, tylko że nie było nic nowego. nie ... tak jest)
Puddle
Och, chciałem powiedzieć „… to nie da ci czasu na utworzenie pliku, chyba że jesteś w systemie Windows”. Przepraszam! Faktem jest, że ta odpowiedź nie jest przenośna i nie wspomina o tym fakcie. (Przykład danych wyjściowych w systemie Linux: pastebin.com/50r5vGBE )
ntninja
@ntnja, to powiesz wszystkim innym?
Puddle
Zostawiłem już kilka innych komentarzy, a wkrótce opublikuję odpowiedź, która działa również na (niedawnym) Linuksie. Ale tak naprawdę jedyną wadą w swoim poście jest to, że odpowiedź tylko dla systemu Windows nie wspomina o tym fakcie. W pytaniu OP nawet konkretnie poprosił o rozwiązanie kompatybilne z Windows i Linux. Dlatego uważam, że bardzo pomocne byłoby dodanie tego „szczegółu” gdzieś na górze, aby ludzie nie byli wprowadzani w błąd, myśląc, że ctime jest tym, czego szukają na wielu platformach.
ntninja
2
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>> 
nieoprawny
źródło
-1: Jak wspomniano w innym miejscu, nie da ci to czasu utworzenia pliku, chyba że korzystasz z systemu Windows (którego odpowiedź nawet nie wspomina!).
ntninja
0

Jeśli podążanie za dowiązaniami symbolicznymi nie jest ważne, możesz również użyć os.lstatwbudowanego.

>>> 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
Low Kian Seong
źródło
To da czas ostatniego czytania (przynajmniej na Unixie), co zdecydowanie nie jest tym, o co proszono.
Mark Amery
0

Warto spojrzeć na crtimebibliotekę, która implementuje międzyplatformowy dostęp do czasu tworzenia pliku.

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
Delgan
źródło
1
Zdecydowanie odradzam to: używa debugfsw Linuksie, który z definicji jest niestabilny, wymaga dostępu do konta root na najwyższym poziomie i praktycznie w każdym aspekcie jest jedną z rzeczy, o których zawsze ostrzegała cię twoja matka. (Ale tak, to prawdopodobnie działa, jeśli naprawdę jesteś zdesperowany i zdarza ci się być prawdziwym superużytkownikiem w systemie bez bezpiecznego rozruchu…)
ntninja
@ntninja Prawdopodobnie nigdy nie użyję go w produkcji, ale może być przydatny do „skryptów domowych”.
Delgan
-2

os.statobejmuje czas utworzenia. Po prostu nie ma definicji st_anything dla elementu, os.stat()który zawiera czas.

Spróbuj tego:

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

Porównaj to ze swoją datą utworzenia w pliku w ls -lah

Powinny być takie same.

Pręt
źródło
6
Źle! os.stat ('feedparser.py') [8] odnosi się do st_mtime, a nie do czasu utworzenia. Proszę zapoznać się z dokumentacją: docs.python.org/library/os.html#os.stat
millerdev
4
Proszę użyć .st_ctime zamiast brzydkich liczb [8].
guettli,
-3

Byłem w stanie uzyskać czas tworzenia na posix, uruchamiając komendę systemową statystyki i analizując dane wyjściowe.

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

Uruchomienie statystyki poza pythonem z terminala (OS X) zwróciło:

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

... gdzie czwartym czasem danych jest tworzenie pliku (zamiast czasu zmiany ctime, jak zauważono w innych komentarzach).

kmarchand
źródło
13
-1: Parsowanie wyjścia przeznaczonego dla ludzi z polecenia powłoki jest bardzo złym pomysłem. To polecenie nie jest nawet kompatybilne krzyżowo.
MestreLion,