Make a backup file: Difference between revisions
m (→{{header|Tcl}}: neater) |
(add Ruby) |
||
Line 23: | Line 23: | ||
(with-standard-io-syntax |
(with-standard-io-syntax |
||
(print data out)))))</lang> |
(print data out)))))</lang> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{untested|Java}} |
{{untested|Java}} |
||
Line 43: | Line 44: | ||
} |
} |
||
}</lang> |
}</lang> |
||
=={{header|Ruby}}== |
|||
This version does not overwrite the backup file if it exists. |
|||
<lang ruby>def backup_and_open(filename) |
|||
filename = File.readlink(filename) if File.symlink?(filename) |
|||
bkup = filename + ".backup" |
|||
Dir.glob(bkup + "*").reverse.each do |fname| |
|||
if m = fname.match(/\.backup\.(\d+)$/) |
|||
File.rename(fname, "%s.%d" % [bkup, m[1].to_i + 1]) |
|||
elsif fname == bkup |
|||
File.rename(bkup, bkup + ".1") |
|||
end |
|||
end |
|||
File.rename(filename, bkup) |
|||
File.open(filename, "w") {|handle| yield handle} |
|||
end |
|||
backup_and_open(ARGV[0]) {|fh| fh.puts "new text"} |
|||
backup_and_open(ARGV[0]) {|fh| fh.puts "some more new text"}</lang> |
|||
Example: |
|||
<pre>$ echo "original" > test.file |
|||
$ ruby backup.rb test.file |
|||
$ ls -l test.file* |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 19 Nov 11 11:19 test.file |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:19 test.file.backup |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:18 test.file.backup.1 |
|||
$ cat test.file |
|||
some more new text |
|||
$ cat test.file.backup |
|||
new text |
|||
$ cat test.file.backup.1 |
|||
original |
|||
$ touch original |
|||
$ ln -s original linkfile |
|||
$ ruby backup.rb linkfile |
|||
$ ls -l linkfile* original* |
|||
lrwxrwxrwx 1 glennj mkgroup-l-d 8 Nov 11 11:22 linkfile -> original |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 19 Nov 11 11:22 original |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:22 original.backup |
|||
-rw-rw-rw-+ 1 glennj mkgroup-l-d 0 Nov 11 11:22 original.backup.1</pre> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
Revision as of 16:19, 11 November 2011
Before writing to a file it is often advisable to make a backup of the original. Creating such a backup file is however also not without pitfalls.
In this task you should create a backup file from an existing file and then write new text to the old file. The following issues should be handled:
- avoid making a copy of the file but instead rename the original and then write a new file with the original filename
- if a copy needs to be made, please explain why rename is not possible.
- keep in mind symlinks, and do not rename or copy the link but the target.
(if there is a link foo -> bar/baz
, then bar/baz
should be renamed to bar/baz.backup
and then the new text should be written to bar/baz
)
- it is assumed that you have permission to write in the target location, thus permission errors need not be handled.
- you may choose the backup filename per preference or given limitations.(it should somehow include the original filename however)
- please try to avoid executing external commands, and especially avoid calling a shell script.
Common Lisp
<lang lisp>(defun save-with-backup (filename data)
(let ((file (probe-file filename))) (rename-file file (concatenate 'string (file-namestring file) ",1")) (with-open-file (out file :direction :output :if-exists :supersede) (with-standard-io-syntax (print data out)))))</lang>
Java
<lang java5>import java.io.PrintWriter; import java.io.FileWriter; import java.nio.file.*;
public class Backup { public static void saveWithBackup(String filename, String... data){ //toRealPath() follows symlinks to their ends Path file = Paths.get(filename).toRealPath(); Path back = Paths.get(filename + ".backup").toRealPath(); Files.move(file, back, StandardCopyOption.REPLACE_EXISTING); try(PrintWriter out = new PrintWriter(new FileWriter(file.toFile()))){ for(String datum:data){ out.println(datum); } } } }</lang>
Ruby
This version does not overwrite the backup file if it exists. <lang ruby>def backup_and_open(filename)
filename = File.readlink(filename) if File.symlink?(filename) bkup = filename + ".backup" Dir.glob(bkup + "*").reverse.each do |fname| if m = fname.match(/\.backup\.(\d+)$/) File.rename(fname, "%s.%d" % [bkup, m[1].to_i + 1]) elsif fname == bkup File.rename(bkup, bkup + ".1") end end File.rename(filename, bkup) File.open(filename, "w") {|handle| yield handle}
end
backup_and_open(ARGV[0]) {|fh| fh.puts "new text"} backup_and_open(ARGV[0]) {|fh| fh.puts "some more new text"}</lang>
Example:
$ echo "original" > test.file $ ruby backup.rb test.file $ ls -l test.file* -rw-rw-rw-+ 1 glennj mkgroup-l-d 19 Nov 11 11:19 test.file -rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:19 test.file.backup -rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:18 test.file.backup.1 $ cat test.file some more new text $ cat test.file.backup new text $ cat test.file.backup.1 original $ touch original $ ln -s original linkfile $ ruby backup.rb linkfile $ ls -l linkfile* original* lrwxrwxrwx 1 glennj mkgroup-l-d 8 Nov 11 11:22 linkfile -> original -rw-rw-rw-+ 1 glennj mkgroup-l-d 19 Nov 11 11:22 original -rw-rw-rw-+ 1 glennj mkgroup-l-d 9 Nov 11 11:22 original.backup -rw-rw-rw-+ 1 glennj mkgroup-l-d 0 Nov 11 11:22 original.backup.1
Tcl
<lang tcl>package require Tcl 8.5
proc backupopen {filename mode} {
set filename [file normalize $filename] if {[file exists $filename]} {
set backups [glob -nocomplain -path $filename ,*] set backups [lsort -dictionary \ [lsearch -all -inline -regexp $backups {,\d+$}]] if {![llength $backups]} { set n 0 } else { set n [regexp -inline {\d+$} [lindex $backups end]] } while 1 { set backup $filename,[incr n] if {![catch {file copy $filename $backup}]} { break } }
} return [open $filename $mode]
}</lang>