Show newest file in directory?


#1

If you have a directory full of files, how can you get the newest file
and oldest file from that directory?

require ‘fileutils’
require ‘find’
require ‘ftools’
require ‘enumerator’

Dir.entries(“C:/New”).each do |filename|
NewestFile = filename.max
OldestFile = filename.min
puts “newest”
puts NewestFile
puts “oldest”
puts OldestFile
end


#2

On Dec 18, 12:36 pm, Mmcolli00 Mom removed_email_address@domain.invalid wrote:

If you have a directory full of files, how can you get the newest file
and oldest file from that directory?

One way…

ages = Dir[“C:/New”].map{|f| [f,File.mtime(f)] }.sort_by{|i|i[1]}

This gives you a sorted list of [filename,age] pairs. Then you can do
this:

newest, oldest = ages[0][0], ages[-1][0]

Or, if you want it in one fell swoop:

newest, oldest = Dir[“C:/New”].map{|f| [f,File.mtime(f)] }.sort_by{|
i|i[1]}.map{|i| i[0]}.values_at(0,-1)

This is known as a “Swartzian Transform”

– Mark.


#3

Thanks Mark.


#4

On 18.12.2008 20:52, Mark T. wrote:

On Dec 18, 12:36 pm, Mmcolli00 Mom removed_email_address@domain.invalid wrote:

If you have a directory full of files, how can you get the newest file
and oldest file from that directory?

One way…

ages = Dir[“C:/New”].map{|f| [f,File.mtime(f)] }.sort_by{|i|i[1]}

IMHO that should read

ages = Dir.entries(“C:/New”).map{|f|
[f,File.mtime(File.join(“C:/New”,f))] }.sort_by{|i|i[1]}

But:

Or, if you want it in one fell swoop:

newest, oldest = Dir[“C:/New”].map{|f| [f,File.mtime(f)] }.sort_by{|
i|i[1]}.map{|i| i[0]}.values_at(0,-1)

We can do better, i.e. #map is superfluous

sorted = Dir.entries(dir).sort_by {|f| File.mtime(File.join(dir,f))}
puts sorted.first, sorted.last

Kind regards

robert


#5

Just a pet peeve… but… Sorts are expensive and should be avoided
when possible. Finding min and max values are prime examples.

So…

newest = Dir.entries(dir).max {|a,b| (File.mtime(File.join(dir,a)) <=>
File.mtime(File.join(dir,b)))}


#6

Thanks Everyone! Great advice!


#7

2008/12/19 Mike C. removed_email_address@domain.invalid:

Just a pet peeve… but… Sorts are expensive and should be avoided when
possible. Finding min and max values are prime examples.

So…

newest = Dir.entries(dir).max {|a,b| (File.mtime(File.join(dir,a)) <=>
File.mtime(File.join(dir,b)))}

While we’re nitpicking… :slight_smile: In this case File.mtime is most likely
the most expensive operation as it does IO (or at least has to travel
into system call land). #max will invoke File.mtime multiple times for
the same file.

So, efficiency wise an explicit one pass solution is probably best:

max = Time.at 0
file = nil

Dir.open(dir) do |d|
d.each do |f|
mt = File.mtime(File.join(dir, f))
if mt > max
max = mt
file = f
end
end
end

puts file

Btw, there is another nice short solution, which unfortunately also
suffers the multiple #mtime per File issue (you can easily see this by
placing “p f;” before the “File.mtime” in the block):

puts Dir.open(dir) {|d| d.max_by {|f| File.mtime(File.join(dir, f))}}

Kind regards

robert