Problem
You want to see when a file was last accessed or modified.
Solution
The result of File.stat contains a treasure trove of metadata about a file. Perhaps the most useful of its methods are the two time methods mtime (the last time anyone wrote to the file), and atime (the last time anyone read from the file).
open("output", "w") { |f| f << "Here's some output. " } stat = File.stat("output") stat.mtime # => Thu Mar 23 12:23:54 EST 2006 stat.atime # => Thu Mar 23 12:23:54 EST 2006 sleep(2) open("output", "a") { |f| f << "Here's some more output. " } stat = File.stat("output") stat.mtime # => Thu Mar 23 12:23:56 EST 2006 stat.atime # => Thu Mar 23 12:23:54 EST 2006 sleep(2) open("output") { |f| contents = f.read } stat = File.stat("output") stat.mtime # => Thu Mar 23 12:23:56 EST 2006 stat.atime # => Thu Mar 23 12:23:58 EST 2006
Discussion
A file's atime changes whenever data is read from the file, and its mtime changes whenever data is written to the file.
There's also a ctime method, but it's not as useful as the other two. Contrary to semi-popular belief, ctime does not track the creation time of the file (there's no way to track this in Unix). A file's ctime is basically a more inclusive version of its mtime. The ctime changes not only when someone modifies the contents of a file, but when someone changes its permissions or its other metadata.
All three methods are useful for separating the files that actually get used from the ones that just sit there on disk. They can also be used in sanity checks.
Here's code for the part of a game that saves and loads the game state to a file. As a deterrent against cheating, when the game loads a save file it performs a simple check against the file's modification time. If it differs from the timestamp recorded inside the file, the game refuses to load the save file.
The save_game method is responsible for recording the timestamp:
def save_game(file) score = 1000 open(file, "w") do |f| f.puts(score) f.puts(Time.new.to_i) end end
The load_game method is responsible for comparing the timestamp within the file to the time the filesystem has associated with the file:
def load_game(file) open(file) do |f| score = f.readline.to_i time = Time.at(f.readline.to_i) difference = ( File.stat(file).mtime - time).abs raise "I suspect you of cheating." if difference > 1 "Your saved score is #{score}." end end
This mechanism can detect simple forms of cheating:
save_game("game.sav") sleep(2) load_game("game.sav") # => "Your saved score is 1000." # Now let's cheat by increasing our score to 9000 open("game.sav", "r+b") { |f| f.write("9") } load_game("game.sav") # RuntimeError: I suspect you of cheating.
Since it's possible to modify a file's times with tools like the Unix touch command, you shouldn't depend on these methods to defend you against a skilled attacker actively trying to fool your program.
See Also
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration