Seeing When a File Was Last Used Problem

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

  • An example in Recipe 3.12, "Running a Code Block Periodically," monitors a file for changes by checking its mtime periodically
  • Recipe 6.20, "Finding the Files You Want," shows examples of filesystem searches that make comparisons between the file times


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



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net