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

I am trying to write a script that looks a a bunch of files and get the last access date. Is there a way to get the access date of a file without changing the access date? If I 'stat' a file it seems to change the access date of the file to today... Any ideas?
  • Comment on Getting the Access Date of a file without changing it

Replies are listed 'Best First'.
Re: Getting the Access Date of a file without changing it
by graff (Chancellor) on Dec 14, 2004 at 05:44 UTC
    When I do this one-liner repeatedly, without actually doing anything else that would read the contents of "test.dat", the output of each run has a higher value than the previous run:
    perl -e 'print -A $ARGV[0],$/' test.dat
    Then, if I do something else that actually reads the file content and run that one-liner on it again, I see a small value. Repeating the command again without reading the file will again lead to increasing values in the output.

    So, by using the "-A" function, I'm getting the age of the file without changing the access time in the process.

    This is with perl 5.8.1 on macosx/darwin/panther (based on BSD unix), but I would expect it to work the same elsewhere. (Then again, maybe this is another one of those things where MS-Windows sets itself apart... I don't know.)

    So, until you show us your code that changes the file's access time just by stat'ing the file, I'll assume you must be doing something wrong. (Maybe after you show us your code, someone can point out what you're doing wrong.)

      Well, it tuns out that the culprits are -T and -B I was also checking to see if the file was a text file or a binary file.
      #!perl my $file=shift; if(!-e $file){die "no file";} if(-d $file){print "directory\n";} if(-T $file){print "text file\n";} if(-B $file){print "binary file\n";} my @stats = stat($file); print "Accessed=$stats[8]\n";
      So, my question (revised) is "Is there a way to determine file type without changing the access date?" Thanks so much.
        One other little nit-pick: if you ever end up doing this on a lot of files (e.g. as returned by File::Find or readdir), it will go noticeably quicker using the "_" (underscore) as a placeholder for "last file stat'ed" -- i.e.:
        use strict; my $file = shift; if ( ! -e $file ) { die "no file" } my $age = -A _; # re-use the stat done by "-e" above if ( -d _ ) { print "directory\n" } elsif ( -T _ ) { print "probably a text file\n" } else { print "probably a binary file\n" } print "Before being read just now, $file was last read ", scalar localtime( $^T - $age*24*3600 ); # $age is in days, so multply to get seconds, subtract from # script's start-time to get original file access time, use # "scalar localtime" to print that in human-readable form
        Note that there may be limits to the reliability of the "-T" (and "-B") tests: they base their decision on reading just the first block or so of a file, but some files that seem to start with text data may contain "binary" (non-text) data later on... It can be a fuzzy distinction in any case.
        Is there a way to determine file type without changing the access date?

        Well, that is a different question, and the answer is probably "no"... Unless of course the files you're dealing with happen to be named (or arranged in directories) in such a way that their type can be determined reliably by the path/name.

        But if directory structure and file names are not sufficient to know the type of file content, then there is simply no way to figure out the type of content without actually reading some of the content. And there you go -- you've read the file and spoiled the access date.

        On some systems (and for super-users on other systems) it may be possible to reset the access date of a file -- that is, get the file age first, then read some content to find out what type of content it has, then reset the access date to it's prior value. You'll need to look it up for your particular OS.

        update: Maybe I misunderstood your question: Is it important that the access date remain as it was after your script is completely done (e.g. to avoid certain consequences for other processes)? Or is it just a matter of wanting to know the how long ago the file was accessed before you try to test its content (i.e. it's okay for the file's access time to have changed after the script is done)?

        If the latter, just put the stat operation for access date before you check for text vs. binary content.