Ho uno script che deve fare alcune cose in base alla data di creazione e modifica dei file, ma deve essere eseguito su Linux e Windows .
Qual è il miglior modo multipiattaforma per ottenere la creazione e la modifica di file date/times
in Python ?
Ho uno script che deve fare alcune cose in base alla data di creazione e modifica dei file, ma deve essere eseguito su Linux e Windows .
Qual è il miglior modo multipiattaforma per ottenere la creazione e la modifica di file date/times
in Python ?
Risposte:
Ottenere una sorta di data di modifica in modo multipiattaforma è semplice: basta chiamare e otterrai il timestamp di Unix di quando il file è stato modificato l'ultima volta.os.path.getmtime(path)
path
Ottenere le date di creazione dei file , d'altra parte, è complicato e dipende dalla piattaforma, differendo anche tra i tre grandi sistemi operativi:
ctime
(documentato su https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx ) memorizza la sua data di creazione. Puoi accedervi in Python tramite os.path.getctime()
o l' .st_ctime
attributo del risultato di una chiamata a os.stat()
. Questo non funzionerà su Unix, dove ctime
è l'ultima volta che gli attributi o il contenuto del file sono stati modificati ..st_birthtime
attributo del risultato di una chiamata a os.stat()
.Su Linux , questo è attualmente impossibile, almeno senza scrivere un'estensione C per Python. Sebbene alcuni file system comunemente usati con Linux memorizzino le date di creazione (ad esempio, ext4
li memorizza st_crtime
), il kernel Linux non offre alcun modo per accedervi ; in particolare, le strutture che restituisce dalle stat()
chiamate in C, a partire dall'ultima versione del kernel, non contengono campi della data di creazione . Puoi anche vedere che l'identificatore st_crtime
attualmente non è presente in nessun punto della sorgente Python . Almeno se sei attivo ext4
, i dati sono collegati agli inode nel file system, ma non esiste un modo conveniente per accedervi.
La cosa migliore su Linux è accedere ai file mtime
, tramite uno os.path.getmtime()
o entrambi gli .st_mtime
attributi di un os.stat()
risultato. Questo ti darà l'ultima volta che il contenuto del file è stato modificato, il che potrebbe essere adeguato per alcuni casi d'uso.
Mettendo tutto insieme, il codice multipiattaforma dovrebbe assomigliare a questo ...
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
unità sotto Linux, e mi piacerebbe imparare cosa succede quando Linux legge i file scritti da Windows, o viceversa, dato che usano in modo st_ctime
diverso.
"w"
, non lo sta sostituendo, apre semplicemente il file esistente e lo tronca. Anche se il contenuto del file non è completamente correlato a ciò che aveva durante la creazione, ti verrà comunque detto che il file è stato "creato" ben prima della versione corrente. Al contrario, gli editor che utilizzano Atomic Replace al momento del salvataggio (il file originale è sostituito da un nuovo file temporaneo in corso di elaborazione) mostrerebbero una data di creazione più recente, anche se hai appena eliminato un carattere. Usa il tempo di modifica, non grub per il tempo di creazione.
stat.st_ctime
è più pertinente perché, in molti casi, il tempo dell'ultima modifica dei metadati può essere il tempo di creazione (almeno ctime
è più vicino al tempo di creazione reale rispetto a mtime
). Pertanto, puoi semplicemente sostituire il tuo frammento con stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime
. Cosa ne pensi? Saluti
ctime
dovrebbe sempre essere uguale o successiva rispetto mtime
, perché un mtime
cambiamento provoca un ctime
cambiamento (in quanto la mtime
stessa è considerata "metadati"). Vedi stackoverflow.com/a/39521489/1709587 dove fornisco alcuni esempi di codice per illustrare questo.
Hai un paio di scelte. Per uno, è possibile utilizzare le funzioni os.path.getmtime
e 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)))
L'altra opzione è utilizzare 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))
Nota : ctime()
non si riferisce all'ora di creazione sui sistemi * nix, ma piuttosto all'ultima modifica dei dati dell'inode. (grazie a Kojiro per aver reso più chiaro questo fatto nei commenti fornendo un link a un post sul blog interessante)
ctime
viene aggiornato ogni volta che lo mtime
fa (dato che si mtime
tratta di "metadati"), e quindi ctime
normalmente è sempre uguale o precedente al mtime
. Trattare ctime
come tempo "creato" quindi non ha alcun senso. -1!
Last modified: Fri Jan 31 11:08:13 2020
e Created: Fri Jan 31 11:08:13 2020
su Linux Ubuntu 16.04!
time.ctime(os.path.getmtime(file))
restituisce 2 tipi di stringhe, a seconda che il file sia stato modificato dal sistema o dall'utente. Se è stata modificata dal sistema, la stringa avrà 2 spazi tra il mese e il giorno. Non so perché
La migliore funzione da utilizzare per questo è os.path.getmtime () . Internamente, questo usa e basta os.stat(filename).st_mtime
.
Il modulo datetime è il timestamp migliore per manipolare, quindi puoi ottenere la data di modifica come un datetime
oggetto come questo:
import os
import datetime
def modification_date(filename):
t = os.path.getmtime(filename)
return datetime.datetime.fromtimestamp(t)
Esempio di utilizzo:
>>> 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
è la cosa più vicina disponibile su Unix (dove non è possibile ottenere le date di creazione), ma sicuramente non è la migliore funzione da usare su Windows, dove ctime
è l'ora della creazione.
os.stat https://docs.python.org/2/library/stat.html#module-stat
modifica: nel codice più recente dovresti probabilmente usare os.path.getmtime () (grazie a Christian Oudard)
ma nota che restituisce un valore in virgola mobile di time_t con frazione di secondi (se il tuo sistema operativo lo supporta)
os.path.getmtime()
è in circolazione da Python 1.5.2 (vedi i vecchi documenti ), rilasciato prima che avessi perso la maggior parte dei miei denti da latte e quasi un decennio prima che tu scrivessi la versione originale di questa risposta.
Esistono due metodi per ottenere il mod time, os.path.getmtime () o os.stat (), ma il ctime non è affidabile multipiattaforma (vedi sotto).
getmtime ( percorso )
Restituisce l'ora dell'ultima modifica del percorso. Il valore restituito è un numero che indica il numero di secondi dall'epoca (vedere il modulo temporale). Sollevare os.error se il file non esiste o è inaccessibile. Novità nella versione 1.5.2. Modificato nella versione 2.3: Se os.stat_float_times () restituisce True, il risultato è un numero in virgola mobile.
stat ( percorso )
Esegue una chiamata di sistema stat () sul percorso indicato. Il valore restituito è un oggetto i cui attributi corrispondono ai membri della struttura stat, vale a dire: st_mode (bit di protezione), st_ino (numero di inode), st_dev (dispositivo), st_nlink (numero di hard link), st_uid (ID utente del proprietario ), st_gid (ID gruppo del proprietario), st_size (dimensione del file, in byte), st_atime (ora dell'accesso più recente), st_mtime (ora dell'ultima modifica del contenuto), st_ctime (dipendente dalla piattaforma; ora dell'ultima modifica dei metadati su Unix o l'ora della creazione su Windows) :
>>> import os
>>> statinfo = os.stat('somefile.txt')
>>> statinfo
(33188, 422511L, 769L, 1, 1032, 100, 926L, 1105022698,1105022732, 1105022732)
>>> statinfo.st_size
926L
>>>
Nell'esempio sopra useresti statinfo.st_mtime o statinfo.st_ctime per ottenere rispettivamente mtime e ctime.
In Python 3.4 e versioni successive, è possibile utilizzare l' interfaccia del modulo pathlib orientata agli oggetti che include wrapper per gran parte del modulo os. Ecco un esempio di come ottenere le statistiche del file.
>>> 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)
Per ulteriori informazioni su ciò che os.stat_result
contiene, consultare la documentazione . Per il tempo di modifica desiderato 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)
Se si desidera il tempo di creazione su Windows o la modifica dei metadati più recente su Unix, si utilizzerà fname.stat().st_ctime
:
>>> ctime = datetime.datetime.fromtimestamp(fname.stat().st_ctime)
>>> print(ctime)
datetime.datetime(2018, 4, 11, 16, 57, 52, 151953)
Questo articolo contiene informazioni più utili ed esempi per il modulo pathlib.
os.stat
restituisce una tupla con nome st_mtime
e st_ctime
attributi. Il tempo di modifica è st_mtime
su entrambe le piattaforme; sfortunatamente, su Windows, ctime
significa "tempo di creazione", mentre su POSIX significa "tempo di cambio". Non sono a conoscenza di alcun modo per ottenere il tempo di creazione su piattaforme POSIX.
dir(..)
una. Ad esempiodir(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))
stampe
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
>>>
Se i seguenti collegamenti simbolici non sono importanti, è possibile utilizzare anche il os.lstat
comando incorporato.
>>> 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
Potrebbe valere la pena dare un'occhiata alla crtime
libreria che implementa l'accesso multipiattaforma al tempo di creazione del file.
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
su Linux che è per definizione instabile, richiede l'accesso root di livello superiore per tutto e praticamente ogni aspetto tende a essere una delle cose di cui tua madre ti ha sempre messo in guardia. (Ma sì, probabilmente funziona se sei davvero disperato e capita di essere il vero superutente su un sistema senza avvio sicuro ...)
os.stat
include il tempo di creazione. Non esiste una definizione di st_anything per l'elemento os.stat()
che contiene il tempo.
Quindi prova questo:
os.stat('feedparser.py')[8]
Confrontalo con la tua data di creazione nel file in ls -lah
Dovrebbero essere uguali.
Sono stato in grado di ottenere il tempo di creazione su posix eseguendo il comando stat del sistema e analizzando l'output.
commands.getoutput('stat FILENAME').split('\"')[7]
In esecuzione stat al di fuori di Python dal Terminale (OS X) restituito:
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
... dove il quarto datetime è la creazione del file (piuttosto che il tempo di cambio ctime come altri commenti hanno notato).