moodwrench has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to work with a directory that contains a very large number of files that are added and removed quickly. I need to generate a list of ctimes and names. I am doing this:
while (defined (my $file = readdir($DH))) { my $cretime=stat("$SPOOL/$file")->ctime or next; push(@files, [$cretime,$file]); }
This works fine unless file is removed before that stat is reached. When that happens, I get the following:

Can't call method "ctime" on an undefined value at /software/bin/transfer.pl line 37.

I don't want to die if the file im stating does not exist, I just want to skip it (aka next in my script). Any ideas?

Replies are listed 'Best First'.
Re: I don't want to die
by ikegami (Patriarch) on Jul 29, 2009 at 15:38 UTC
    my $stat = stat("$SPOOL/$file") or next; push @files, [ $stat->ctime, $file ];

    Note that ctime is the inode change time, not creation time.

Re: I don't want to die
by moritz (Cardinal) on Jul 29, 2009 at 15:36 UTC
    Use the BLOCK form of eval to catch the exception. Or inspect the return value of stat() before calling a method on it.
Re: I don't want to die
by SuicideJunkie (Vicar) on Jul 29, 2009 at 15:41 UTC
    eval can catch the dies:
    while (defined (my $file = readdir($DH))) { my $cretime; eval {$cretime=stat("$SPOOL/$file")->ctime; 1;} or next; push(@files, [$cretime,$file]); }
    Note: the 1; is added to ensure the eval returns true on success.
      Thanks.. eval works perfectly. I used ctime as I want the time that the file was added to the directory by another script. So far ctime seems to return the correct files and my script continues to run after the eval
      Thanks again!

        Thanks.. eval works perfectly.

        Not really. Why cause an error and then silence *all* errors when it's easier to not cause it in the first place?

        my ($cretime) = eval { stat("$SPOOL/$file")->ctime } or next; push @files, [ $cretime, $file ];
        vs
        my $stat = stat("$SPOOL/$file") or next; push @files, [ $stat->ctime, $file ];

        I used ctime as I want the time that the file was added to the directory by another script.

        ctime definitely doesn't return what you want.

        $ perl -MFile::stat -le'print "".localtime( stat("a")->ctime )' Wed Jul 29 12:13:21 2009 $ chmod u+r a $ perl -MFile::stat -le'print "".localtime( stat("a")->ctime )' Wed Jul 29 12:13:46 2009
        As ikegami points out, UNIX based systems don't actually store creation time anywhere. A better bet is usually to have the script that adds the files to the directory append the timestamp to the end of the file name.