views:

1099

answers:

3

I'd like to be able to show the progress of a file copy operation when copying files using Ruby (currently using FileUtils.cp) I've tried setting the verbose option to true but that just seems to show me the copy command issued.

I'm running this script from command line at the moment so ideally I'd like to be able to present something like SCP does when it copies files, but I'm not too fussed about the presentation as long as I can see the progress.

+4  A: 

Roll your own using IO.syswrite, IO.sysread.

First, decide length of progress bar (in chars).. then this pseudo code should do it (NOT TESTED):

infile = File.new("source", "r")
outfile = File.new("target", "w")

no_of_bytes = infile.length / PROGRESS_BAR_LENGTH

buffer = infile.sysread(no_of_bytes)
while buffer do
 outfile = syswrite(buffer)
 update_progress_bar()
 buffer = infile.sysread(no_of_bytes)
end

where update_progress_bar() is your method to increment the progress bar by one char. The above is not tested and will probably make ruby purists ill. In particular an EOFException might mess up the loop. Also you will need some way of making sure that all the bytes are written if no_of_bytes is not an integer.

pisswillis
A great starting point, but as I couldn't edit it I had to add my own answer with my working code.
DEfusion
+2  A: 

Or you could just hack it to use scp, if that's the progress bar you like:

def copy(source, dest)
  `scp #{source} localhost:#{dest}`
end

You'll have to make sure the source and dest names are properly escaped for a system call. The localhost: tag makes scp copy the files as it does between computers, so it will show a progress bar.

rampion
What a great idea, didn't think of that.
DEfusion
+5  A: 

As I don't have enough rep to edit answers yet here is my version based on pisswillis answer, I found a progress bar gem which I'm also using in my example. I have tested this and it has worked OK so far, but it could do with some cleaning up:

require 'rubygems'
require 'progressbar'

in_name     = "src_file.txt"
out_name    = "dest_file.txt"

in_file     = File.new(in_name, "r")
out_file    = File.new(out_name, "w")

in_size     = File.size(in_name)
batch_bytes = ( in_size / 100 ).ceil
total       = 0
p_bar       = ProgressBar.new('Copying', 100)

buffer      = in_file.sysread(batch_bytes)
while total < in_size do
 out_file.syswrite(buffer)
 p_bar.inc
 total += batch_bytes
 if (in_size - total) < batch_bytes
   batch_bytes = (in_size - total)
 end
 buffer = in_file.sysread(batch_bytes)
end
p_bar.finish
DEfusion
nicely done.And thanks for introducing me to the progressbar gem.
pisswillis