2017-05-18 2 views
-2

Ich versuche, ein ziemlich großes Dateisystem aufzuräumen. Ich verwende die stat Funktion, um die Änderungszeit jeder Datei zu erhalten.Fehler in der abgelaufenen Zeit seit der Änderung der Datei mit "DateTime"

Gemäß perldoc -f stat ist das zehnte Element der zurückgegebenen Liste die letzte in Sekunden seit der Epoche geänderte Zeit.

Ich benutze DateTime->from_epoch und subtrahieren DateTime->now das Alter des fule

#!/usr/bin/perl 

    use strict; 
    use warnings; 

    use DateTime; 

    my $now = DateTime->now(); 
    #my $now = DateTime->now(time_zone => "America/New_York"); 

    $self->{dir} = '/tmp/test'; 
    opendir(DIR, $self->{dir}) or die [email protected]; 
    my @files = grep(/\.txt$/, readdir(DIR)); 
    closedir(DIR); 

    for (@files) { 

      my $file = stat($self->{dir} . '/' . $_); 
      my $mtime = DateTime->from_epoch(epoch => $file->mtime); 
      #my $mtime = DateTime->from_epoch(epoch => $file->mtime, time_zone=> "America/New_York"); 
      my $elapsed = $now - $mtime; 
      push(@{$self->{stale}}, {file => $self->{dir} . '/' . $_, mtime => $elapsed->in_units('minutes')}) if $elapsed->in_units('minutes') > 15; 
      push(@{$self->{remove}}, {file => $self->{dir} . '/' . $_, mtime => $elapsed->in_units('days')}) if $elapsed->in_units('days') > 10; 
    } 

zu berechnen Wenn ich manuell Testdateien erstellen und die Änderung der Zeit ändern, ist das Ergebnis um 30 Tage

$ touch /tmp/test/test{100..104}.txt -d '-45 days' 
$ perl MTIME.pm 
$VAR1 = { 
      'mtime' => 15, 
      'file' => '/tmp/test/test100.txt' 
     }; $VAR1 = { 
      'mtime' => 15, 
      'file' => '/tmp/test/test104.txt' 
     }; $VAR1 = { 
      'mtime' => 15, 
      'file' => '/tmp/test/test103.txt' 
     }; $VAR1 = { 
      'mtime' => 15, 
      'file' => '/tmp/test/test101.txt' 
     }; $VAR1 = { 
      'mtime' => 15, 
      'file' => '/tmp/test/test102.txt' 
     }; 

off Ich habe versucht DateTime Objekte mit und ohne die Zeitzone ohne Unterschied in den Ergebnissen festgelegt.

$ touch /tmp/test/test{100..104}.txt -d '-45 days' 
$ touch /tmp/test/test{105..110}.txt 
$ ll /tmp/test 
total 11 
-rw-r--r-- 1 root root 0 Apr 3 19:31 test100.txt 
-rw-r--r-- 1 root root 0 Apr 3 19:31 test101.txt 
-rw-r--r-- 1 root root 0 Apr 3 19:31 test102.txt 
-rw-r--r-- 1 root root 0 Apr 3 19:31 test103.txt 
-rw-r--r-- 1 root root 0 Apr 3 19:31 test104.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test105.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test106.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test107.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test108.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test109.txt 
-rw-r--r-- 1 root root 0 May 18 19:30 test110.txt 

Arbeitslösung:

#!/usr/bin/perl 

use strict; 
use warnings 'all'; 

use Data::Dumper; 

my $self = bless { }, 'My::Class'; 

my @files = glob '/tmp/test/*.txt'; 

for (@files) { 
     my $days = int(-M $_); 
     my $mins = int((time - (stat $_)[9])/60); 
     my $item = { 
       file => $_, 
       days => $days, 
       minutes => $mins 
     }; 
     push @{ $self->{remove} }, $item if $days > 10; 
     push @{ $self->{stale} }, $item if $mins > 15; 
} 

print Dumper $self; 
+1

Haben Sie darüber nachgedacht '-M $ file'? Es ist der Unterschied zwischen der Startzeit des Skripts (so, "jetzt") und der Zeit der letzten Änderung, was scheint, was Sie brauchen. Siehe [Dateitests (-X)] (http://perldoc.perl.org/functions/-X.html). – zdim

+1

Bitte überprüfen Sie, was Sie gepostet haben. Das '$ self -> {dir} ...' sollte nicht unter 'strict' kompiliert werden (und macht keinen Sinn wie es ist) – zdim

+0

Sie werden feststellen, dass, um die volle Dauer zu erhalten, nur in_units ('Tage') aufgerufen wird nicht gut genug. Sehen Sie sich die DateTime :: Duration-Dokumente an, da Sie Monate oder sogar Jahre verpasst haben, ohne es zu merken. Arbeiten direkt mit Epochen Zahlen und Sekunden kann hier einfacher sein. – bytepusher

Antwort

0

Ihre Frage ist schwer zu verstehen, weil Sie ein objektorientiertes Modul schreiben und es dann als Programm ausführen. Der Code, den Sie anzeigen, wird nicht kompiliert, hauptsächlich weil $self nie deklariert oder definiert wird. Wenn Sie auf nützliche Antworten hoffen, dann stellen Sie bitte ein komplettes Programm, dass wir ausführen können und das Problem zeigt, das Sie über

Ich kann nicht versuchen, Ihr Programm und das Problem für mich selbst sehen, aber es gibt zwei offensichtliche Verbesserungen zu machen

  • Es ist viel einfacher, um einen Anruf zu glob zu machen, als ein Verzeichnis zu öffnen und zu lesen, entfernen Sie die Dateien, die Sie nicht wollen, und erstellen Sie das Verzeichnis zu jeder Datei den Pfad durch Zugabe zurück

  • Sie können den integrierten Operator -M verwenden, um das zu ermitteln Alter einer Datei in Gleitkommaoperationen Tage

ich dieses geschrieben habe, die ein leeres Objekt in der Klasse erstellt My::Class und fügt Daten zu. Es enthält die Ideen, über die ich gesprochen habe, aber wie Ihr eigener Code liefert keine Ausgabe. Hoffentlich werden Sie verstehen, wie Sie dies in Ihre eigene Struktur zu interpretieren

Das einzige Problem, das Sie möglicherweise haben, ist, dass die mtime Felder Fließkomma Tage sind.Sie können int oder POSIX::ceil je nachdem, was die Werte für

verwendet werden, anwenden möchten
use strict; 
use warnings 'all'; 

my $self = bless { }, 'My::Class'; 

my @files = glob '/temp/text/*.txt'; 

for my $file (@files) { 

    my $age = -M $file; 

    if ($age >= 10.0) { 

     my $item = { 
      file => $file, 
      mtime => $age, 
     }; 

     push @{ $self->{remove} }, $item; 

     push @{ $self->{stale} }, $item if $age >= 15.0; 
    } 
} 
+0

Entschuldigung für die fehlende Vollständigkeit im Beispiel. Das Stück, das ich hier gepostet habe, ist eine Methode in einem Modul, das mehrere enthält, und das ganze Ding zu veröffentlichen wäre aufgebläht und zeitaufwendig gewesen, um es zu bereinigen. Zum Debuggen/Testen habe ich vorübergehend das Modul __PACKAGE __-> neu-> testen, um die Ausgabe zu überprüfen. Ich werde dein Beispiel morgen versuchen und sehen, wie es funktioniert, hatte ich nicht überlegt, glob. Ich bin nicht gerade ein Perl-Pro, und die meisten meiner Skripte befassen sich nicht mit Dateisystemen. Angesichts der sensiblen Natur der Daten möchte ich sicherstellen, dass ich mich dem bestmöglichen Weg annähere. Wird 2morrow testen. – Mose

+0

Außerdem hatte ich anfänglich mit -M begonnen, aber $ self -> {stale} speichert das Alter in Minuten im Gegensatz zu Tagen, während $ self -> {remove} das Alter in Tagen speichert. -M funktioniert viel besser als DateTime, aber ich bekam nicht die Ergebnisse, die ich erwartet hatte (Datums/Zeiten sind ein Stolperstein für mich), also dachte ich, DateTime könnte die sicherere Option sein, wenn auch nicht die idealste . – Mose

0

Abgesehen von allen anderen möglichen Problemen:

my $elapsed = $now - $mtime; 
push(@{$self->{remove}}, { 
    file => $self->{dir} . '/' . $_, 
    mtime => $elapsed->in_units('days') 
}) 
if $elapsed->in_units('days') > 10; 

nicht tut, was Sie erwarten.

Sie könnten ein DateTime :: Duration-Objekt von 10 Tagen erstellen und damit vergleichen. Um dies zu tun, benötigen Sie eine Basis Datetime.

Zum Beispiel

my $base = DateTime->now; 
my $ten_days = DateTime::Duration->new(days => 10); 

if (DateTime::Duration->compare($elapsed,$ten_days,$base) == 1){ 
    push(@{$self->{remove}}, { 
     file => $self->{dir} . '/' . $_, 
     mtime => $elapsed->in_units('days') 
    }) 
} 

Ich würde vorschlagen, berechnen aber einfach die Sekunden in 10 Tagen und sehen, ob die verstrichene Zeit größer als das ist, wie es viel einfacher scheint, und stat kehrt sowieso Epoche.

+0

Oder verwenden Sie "-M", die die Mathematik für Sie tut und ihre Eingabe in Tagen nimmt. –

+2

Re "* Ich würde jedoch vorschlagen, einfach die Sekunden in 10 Tagen zu berechnen *" Das ist eigentlich sehr kompliziert. 'DateTime :: Duration-> compare ($ veraltet, $ ten_days, $ base) == 1 'ist in der Tat die einfache Art, das zu tun. Was das OP jedoch tun könnte, ist ein Vergleich mit "time-10 * 24 * 60 * 60". Es ist vielleicht nicht genau 10 Tage her, aber es ist wahrscheinlich nahe genug für das OP. – ikegami

Verwandte Themen