Make a backup file: Difference between revisions

Added FreeBASIC
(a)
(Added FreeBASIC)
 
(27 intermediate revisions by 15 users not shown)
Line 14:
Some examples on this page assume that the original file already exists. They might fail if some user is trying to create a new file.
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">V targetfile = ‘pycon-china’
fs:rename(fs:path:canonical(targetfile), fs:path:canonical(targetfile)‘.bak’)
V f = File(fs:path:canonical(targetfile), ‘w’)
f.write(‘this task was solved during a talk about rosettacode at the PyCon China in 2011’)
f.close()</syntaxhighlight>
 
=={{header|Applesoft BASIC}}==
Due to all the pitfalls in this task it is helpful to turn on debugging by default. It is also helpful, to show each DOS 3.3 Command, by entering MON C before running the program. There is an extra PRINT statement in line 540 to work-around an issue with the display of DOS 3.3 commands after an error occurs. Setting ERASEANYBACKUP will delete the backup file if it already exists. Delete lines 180 to 230 with DEL 180,230 and it is possible with DOS 3.3 to have backup files all with the same name due to a pitfall in the RENAME Command.
<syntaxhighlight lang="gwbasic"> 100 ERASEANYBACKUP = FALSE
110 DEBUG = NOT FALSE
120 F$ = "FILE"
130 LET B$ = "BACKUP " + F$
140 LET D$ = CHR$ (4)
150 N$ = F$
160 GOSUB 400"FILE EXISTS?"
170 IF NOT E GOTO 260"MAKE NEW FILE"
180 N$ = B$
190 GOSUB 400"FILE EXISTS?"
200 IF NOT E GOTO 240"KEEP FILE AS BACKUP FILE"
210 IF DEBUG AND NOT ERASEANYBACKUP THEN PRINT " *** "B$" WON'T BE DELETED.";
220 IF NOT ERASEANYBACKUP THEN STOP
230 PRINT D$"DELETE "B$
 
240 IF DEBUG THEN PRINT " >>> MAKING A BACKUP FILE."
250 PRINT D$"RENAME "F$","B$
 
260 IF DEBUG THEN PRINT " >>> MAKING A NEW FILE."
270 PRINT D$"OPEN "F$
280 PRINT D$"WRITE "F$
290 PRINT "THE NEW CONTENT OF THE FILE."
300 PRINT D$"CLOSE "F$
310 END
 
400 ONERR GOTO 500"CATCH"
410 PRINT D$"VERIFY "N$
420 POKE 216,0: REM ONERR OFF
430 LET E = 1
440 IF DEBUG THEN PRINT " <<< "N$" EXISTS."
450 RETURN
500 LET E = PEEK (222) < > 6
510 POKE 216,0: REM ONERR OFF
520 IF E THEN RESUME : REM THROW
530 CALL - 3288: REM RECOVER
540 PRINT
550 IF DEBUG THEN PRINT " <<< "N$" DOES NOT EXIST."
560 RETURN</syntaxhighlight>
<syntaxhighlight lang="text">DELETE FILE
DELETE BACKUP FILE
MON C</syntaxhighlight>
<syntaxhighlight lang="gwbasic">RUN</syntaxhighlight>
{{out}}
<pre>
VERIFY FILE
<<< FILE DOES NOT EXIST.
>>> MAKING A NEW FILE.
OPEN FILE
WRITE FILE
CLOSE FILE
</pre>
<syntaxhighlight lang="gwbasic">RUN</syntaxhighlight>
{{out}}
<pre>
VERIFY FILE
<<< FILE EXISTS.
VERIFY BACKUP FILE
<<< BACKUP FILE DOES NOT EXIST.
>>> MAKING A BACKUP FILE.
RENAME FILE,BACKUP FILE
>>> MAKING A NEW FILE.
OPEN FILE
WRITE FILE
CLOSE FILE
</pre>
<syntaxhighlight lang="gwbasic">RUN</syntaxhighlight>
{{out}}
<pre>
VERIFY FILE
<<< FILE EXISTS.
VERIFY BACKUP FILE
<<< BACKUP FILE EXISTS.
*** BACKUP FILE WON'T BE DELETED.
BREAK IN 220
</pre>
=={{header|AutoHotkey}}==
<langsyntaxhighlight lang="autohotkey">targetfile := "ahk-file"
if FileExist(targetfile)
FileMove, %targetfile%, %targetfile%.bak
Line 27 ⟶ 113:
}
file.Write("This is a test string.`r`n")
file.Close()</langsyntaxhighlight>
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f MAKE_A_BACKUP_FILE.AWK filename(s)
# see: http://www.gnu.org/software/gawk/manual/gawk.html#Extension-Sample-Inplace
Line 47 ⟶ 133:
exit(0)
}
</syntaxhighlight>
</lang>
 
=={{header|Batch File}}==
<syntaxhighlight lang="dos">
@echo off
setlocal enabledelayedexpansion
 
:: Takes file input as param #1
set "filePath=%~1"
set "fileName=%~xn1"
 
:: Save file contents of original file to array line[n]
set i=0
for /f "usebackq delims=" %%a in ("%filePath%") do (
set /a i+=1
set "line[!i!]=%%a"
)
 
:: Rename original file with .backup extension
ren "%filePath%" "%fileName%.backup"
 
:: Rewrite a new file with the name of the original
echo !line[1]!>"%filePath%"
for /l %%i in (2,1,%i%) do echo !line[%%i]!>>"%filePath%"
</syntaxhighlight>
 
=={{header|Common Lisp}}==
Appends a version number and increments it on each backup
<langsyntaxhighlight lang="lisp">(defun parse-integer-quietly (&rest args)
(ignore-errors (apply #'parse-integer args)))
 
Line 69 ⟶ 179:
(rename-file file (get-next-version file))
(with-open-file (out file :direction :output)
(print data out))))</langsyntaxhighlight>
 
=={{header|Elixir}}==
<syntaxhighlight lang="elixir">defmodule RC do
<lang elixir></lang>
def backup_file(filename) do
backup = filename <> ".backup"
case File.rename(filename, backup) do
:ok -> :ok
{:error, reason} -> raise "rename error: #{reason}"
end
File.cp!(backup, filename)
end
end
 
hd(System.argv) |> RC.backup_file</syntaxhighlight>
 
=={{header|Forth}}==
<syntaxhighlight lang="forth">
: backup ( addr u -- )
2dup pad place s" .bak" pad +place
2dup pad count rename-file throw
w/o create-file throw
s" This is a test string." 2 pick write-file throw
close-file throw ;
 
s" testfile" backup</syntaxhighlight>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="vbnet">Sub saveWithBackup(filePath As String, lines() As String)
Dim As String origPath = filePath
If Len(Dir(origPath)) > 0 Then
Dim As String backupPath = origPath & ".backup"
Name(origPath, backupPath) 'Renames a file on disk
End If
Open origPath For Output As #1
For i As Integer = 1 To Ubound(lines)
Print #1, lines(i)
Next i
Close #1
End Sub
 
Dim lines(1 To 3) As String => {"fourth", "fifth", "sixth"}
saveWithBackup("original.txt", lines())
 
Dim As String linea
' check it worked
Print "Current contents of original.txt:"
Open "original.txt" For Input As #1
While Not Eof(1)
Line Input #1, linea
Print linea
Wend
Close #1
 
Print !"\nContents of original.txt.backup:"
Open "original.txt.backup" For Input As #1
While Not Eof(1)
Line Input #1, linea
Print linea
Wend
Close #1
 
Sleep</syntaxhighlight>
{{out}}
Contents of 'original.txt' ''before'' the program is run and of 'original.txt.backup' ''after'' it is run:
<pre>
first
second
third
</pre>
 
Contents of 'original.txt' ''after'' the program is run:
<pre>
fourth
fifth
sixth
</pre>
 
Line 81 ⟶ 260:
===Rename===
This is the technique of the task description.
<langsyntaxhighlight lang="go">package main
 
import (
Line 113 ⟶ 292:
fmt.Println(err)
}
}</langsyntaxhighlight>
===Copy===
Alternative technique copies an existing file to make the backup copy, then updates the origial file. In an attempt to keep operations atomic, the original file is opened as the first operation and is not closed until all operations are complete. In an attempt to avoid data loss, the original file is not modified until the backup file is closed.
<langsyntaxhighlight lang="go">package main
 
import (
Line 196 ⟶ 375:
// backup complete (as long as err == nil)
return
}</langsyntaxhighlight>
 
=={{header|Java}}==
{{works with|Java|7+}}
<langsyntaxhighlight lang="java5">import java.io.PrintWriterFile;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.*;
 
public class Backup {
public static void saveWithBackup(String filename, String... data){
throws IOException {
//toRealPath() follows symlinks to their ends
Path file = Paths.get(filename).toRealPath();
Line 223 ⟶ 405:
}
}
 
}</lang>
public static void main(String[] args) {
try {
saveWithBackup("original.txt", "fourth", "fifth", "sixth");
} catch (IOException e) {
System.err.println(e);
}
}
}</syntaxhighlight>
 
Contents of 'original.txt' ''before'' the program is run and of 'original.txt.backup' ''after'' it is run:
<pre>
first
second
third
</pre>
 
Contents of 'original.txt' ''after'' the program is run:
<pre>
fourth
fifth
sixth
</pre>
 
{{works with|Java|1.5+}}
<langsyntaxhighlight lang="java5">import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
Line 246 ⟶ 451:
output.close();
}
 
}</lang>
public static void main(String[] args) {
try {
saveWithBackup("original.txt", "fourth", "fifth", "sixth");
} catch (IOException e) {
System.err.println(e);
}
}
}</syntaxhighlight>
 
{{out}}
Same as version 7+ example.
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<syntaxhighlight lang="julia">targetfile = "pycon-china"
mv(realpath(targetfile), realpath(targetfile) * ".bak")
# "a+" for permissions of reading, writing, creating
open(targetfile, "w+") do io
println(io, "this task was solved during a talk about rosettacode at the PyCon China in 2011")
end</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Java}}
<syntaxhighlight lang="scala">// version 1.1.51
 
import java.io.File
 
fun saveWithBackup(fileName: String, vararg data: String) {
val orig = File(fileName)
// canonicalPath follows symlinks to their ends
val backup = File(orig.canonicalPath + ".backup")
orig.renameTo(backup)
val pw = orig.printWriter()
for (i in data.indices) {
pw.print(data[i])
if (i < data.lastIndex) pw.println()
}
pw.close()
}
 
fun main(args: Array<String>) {
saveWithBackup("original.txt", "fourth", "fifth", "sixth")
}</syntaxhighlight>
 
Contents of 'original.txt' ''before'' the program is run and of 'original.txt.backup' ''after'' it is run:
<pre>
first
second
third
</pre>
 
Contents of 'original.txt' ''after'' the program is run:
<pre>
fourth
fifth
sixth
</pre>
 
=={{header|Lasso}}==
<langsyntaxhighlight Lassolang="lasso">local(file2use = 'input.txt')
 
// create file
Line 268 ⟶ 531:
// create new file with new contents
local(nf = file(#file2use))
#nf->doWithClose => { #nf->writeBytes(#contents_of_f->asBytes) }</langsyntaxhighlight>
 
=={{header|Locomotive Basic}}==
 
AMSDOS has automatic one-level backups which also work from Locomotive BASIC: If e.g. the file <tt>test.bas</tt> is saved, the data gets written to <tt>test.$$$</tt>. When the file is closed a preexisting <tt>test.bas</tt> gets renamed to <tt>test.bak</tt> and finally <tt>test.$$$</tt> is renamed to <tt>test.bas</tt>. (These backups affect all file types, not just BASIC source code.)
 
=={{header|Nim}}==
In case the backup cannot be done, an exception is raised.
<syntaxhighlight lang="nim">import os, strutils
 
const
Suffix = ".backup"
Dir = "working_dir"
SubDir = "dir"
f1 = "f1.txt"
f2 = "f2.txt"
f3 = SubDir / "file.txt"
 
proc newBackup(path: string): string =
## Create a backup file. Return the path to this file.
if not path.fileExists():
raise newException(IOError, "file doesn't exist.")
let path = path.expandFilename() # This follows symlinks.
result = path & Suffix
moveFile(path, result)
result = result.relativePath(getCurrentDir())
 
# Prepare test files.
let oldDir = getCurrentDir()
createDir(Dir)
setCurrentDir(Dir)
createDir(SubDir)
f1.writeFile("This is version 1 of file $#" % f1)
f3.writeFile("This is version 1 of file $#" % f3)
createSymlink(f3, f2)
 
# Display initial state.
echo "Before backup:"
echo f1, ": ", f1.readFile
echo f2, " → ", f3, ": ", f2.readFile()
 
# Create backups.
echo "\nBackup of regular file:"
let f1Backup = newBackup(f1)
f1.writeFile("This is version 2 of file $#" % f1)
echo f1, ": ", f1.readFile()
echo f1Backup, ": ", f1Backup.readFile()
 
echo "\nBackup of symbolic link to file:"
let f2Backup = newBackup(f2)
f2.writeFile("This is version 2 of file $#" % f3)
echo f2, " → ", f3, ": ", f2.readFile()
echo f2Backup, ": ", f2Backup.readFile()
 
# Cleanup.
setCurrentDir(oldDir)
removeDir(Dir)</syntaxhighlight>
 
{{out}}
<pre>Before backup:
f1.txt: This is version 1 of file f1.txt
f2.txt → dir/file.txt: This is version 1 of file dir/file.txt
 
Backup of regular file:
f1.txt: This is version 2 of file f1.txt
f1.txt.backup: This is version 1 of file f1.txt
 
Backup of symbolic link to file:
f2.txt → dir/file.txt: This is version 2 of file dir/file.txt
dir/file.txt.backup: This is version 1 of file dir/file.txt</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">use strict;
use warnings;
 
sub backup {
my($filepath,$limit,$ext) = @_;
my $abs = readlink $filepath // $filepath; # always resolve symlinks
for my $bnum (reverse 1 .. $limit-1) {
rename "$abs$ext$bnum", "$abs$ext" . ++$bnum if -e "$abs$ext$bnum";
}
 
if (-e $abs) {
if ($limit > 0) {
my $orig = $abs . $ext . '1';
rename $abs, $orig;
open(IN, '<', $orig) or die "can't open $orig: $!";
open(OUT, '>', $abs) or die "can't open $abs: $!";
 
my $blksize = (stat IN)[11] || 2**14; # preferred block size?
my $buf;
while (my $len = sysread IN, $buf, $blksize) {
die "System read error: $!\n" if !defined $len;
my $offset = 0;
while ($len) { # Handle partial writes.
defined(my $written = syswrite OUT, $buf, $len, $offset)
or die "System write error: $!\n";
$len -= $written;
$offset += $written;
};
}
close(IN);
close(OUT);
}
} else {
warn "File not found: $abs" and return 0;
}
$abs
}
 
# back up this program
backup($0,3,'.bk');</syntaxhighlight>
 
=={{header|Phix}}==
{{trans|Go}}
<syntaxhighlight lang="phix">targetfile = get_proper_path("test.txt")
if not rename_file(targetfile, targetfile&".bak", overwrite:=true) then
puts(1,"warning: could not rename file\n")
end if
integer fn = open(targetfile,"w")
if fn=-1 then
puts(1,"error: cannot open file for writing\n")
else
puts(fn,"this task was translated from the Python entry\n")
close(fn)
end if</syntaxhighlight>
Before basing anything on the above code, though, I would recommend you take a look at <br>
function saveFile in demo\edix\edix.exw, which does this sort of thing for real: <br>
test.txt -> test.0001.txt, test.0002.txt, etc, in subdirectories \backups, \backups.0001, \backups.0002, etc.
 
=={{header|PicoLisp}}==
PicoLisp makes use of external commands as much as possible (at least for not time-critical operations), to avoid duplicated functionality.
<langsyntaxhighlight PicoLisplang="picolisp">(let Path (in '(realpath "foo") (line T))
(call 'mv Path (pack Path ".backup"))
(out Path
(prinl "This is the new file") ) )</langsyntaxhighlight>
 
=={{header|Pike}}==
<langsyntaxhighlight Pikelang="pike">string targetfile = "pycon-china";
targetfile = System.resolvepath(targetfile);
mv(targetfile, targetfile+"~");
Stdio.write_file(targetfile, "this task was solved at the pycon china 2011");</langsyntaxhighlight>
 
=={{header|Python}}==
Using [https://docs.python.org/library/os.html os library]
<lang Python>
<syntaxhighlight lang="python">
import os
targetfile = "pycon-china"
Line 295 ⟶ 683:
f.write("this task was solved during a talk about rosettacode at the PyCon China in 2011")
f.close()
</syntaxhighlight>
</lang>
Or using a newer [https://docs.python.org/library/pathlib.html pathlib library] (Python >= 3.4):
<syntaxhighlight lang="python">
from pathlib import Path
 
filepath = Path("original_file")
filepath.rename(filepath.with_suffix('.bak'))
with filepath.open('w') as file:
file.write("New content")
</syntaxhighlight>
 
=={{header|Racket}}==
Line 301 ⟶ 698:
This version keeps unlimited backups, with <tt>*.bak</tt> being the freshest one, <tt>*.bak1</tt> is an older backup, etc. So each backup moves all existing names up.
 
<syntaxhighlight lang="racket">
<lang Racket>
#lang racket
 
Line 319 ⟶ 716:
 
(revise "fff")
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2017.10}}
 
<syntaxhighlight lang="raku" line># Back up the given path/filename with a default extension .bk(n)
# where n is in the range 1 - $limit (default 3).
# Prints 'File not found' to STDERR if the file does not exist.
# Will not do anything if limit is set to less than 1.
# Will not follow symlinks by default.
 
sub backup (Str $filepath, Int :$limit = 3, Str :$ext = 'bk', Bool :$follow-symlinks = False) {
my $abs = $follow-symlinks ?? $filepath.IO.resolve.absolute !! $filepath.IO.absolute;
for (1 ..^ $limit).reverse -> $bnum {
if "{$abs}.{$ext}{$bnum}".IO.e {
"{$abs}.{$ext}{$bnum}".IO.rename: "{$abs}.{$ext}{$bnum + 1}";
}
}
if $abs.IO.e {
if $limit > 0 {
$abs.IO.rename: "{$abs}.{$ext}1";
my $in = "{$abs}.{$ext}1".IO.open :r :bin or note $! and return False;
my $out = $abs.IO.open :w :bin or note $! and return False;
my $buffer-size = 32768; # 32Kb
while my $buf = $in.read($buffer-size) { $out.write($buf) };
close $in;
close $out;
}
} else {
note "File not found: $abs" and return False;
}
$abs # return filepath on success
}
 
# back up this program
backup $*PROGRAM-NAME;
 
# Optionally, specify limit, back-up extension pattern and whether to follow symlinks.
# Optional parameters can be in any order, in any combination.
backup 'myfile', :follow-symlinks, :limit(2), :ext('bak');</syntaxhighlight>
 
=={{header|REXX}}==
This REXX version executes under DOS or DOS under Windows.
<langsyntaxhighlight lang="rexx">/*REXX pgmprogram creates a backup file (for a given file), then overwrites the old file.*/
parse arg oFID . /*get a required argument from the C.L.*/
parse arg oFID .
if oFID=='' then do; say '***error*** no fileID was specified.'; exit 13; end /*No argument? Then issue an err msg.*/
tFID=oFID'.$$$' say /'***error***create temporaryno namefileID forwas the backupspecified.*/'
call lineout oFID exit /*close the file (in case it's open). */13
call lineout tFID /* " " " " " " " */end
tFID= oFID'ERASE.$$$' tFID /*deletecreate thetemporary backupname filefor (ifthe it exists)backup.*/
'RENAME'call lineout oFID tFID /*renameclose the original file to backup.(in case it's open). */
call lineout oFID,'═══ThistFID is line 1.' /*write one line" " " " " " to" the original file. */
'ERASE' tFID /*stickdelete athe forkbackup infile (if it, we're all done. exists)*/</lang>
'RENAME' oFID tFID /*rename the original file to backup. */
call lineout oFID, '═══This is line 1.' /*write one line to the original file. */
/*stick a fork in it, we're all done. */</syntaxhighlight>
The contents of the original file (before execution): &nbsp; '''A.FILE''':
<pre>
Line 357 ⟶ 797:
=={{header|Ruby}}==
This version does not overwrite the backup file if it exists.
<langsyntaxhighlight lang="ruby">def backup_and_open(filename)
filename = File.realpath(filename)
bkup = filename + ".backup"
Line 375 ⟶ 815:
end
 
1.upto(12) {|i| backup_and_open(ARGV[0]) {|fh| fh.puts "backup #{i}"}}</langsyntaxhighlight>
 
Example:
Line 410 ⟶ 850:
backup 1
original</pre>
 
=={{header|Scala}}==
===Java Interoperability===
<syntaxhighlight lang="scala">import java.io.{File, PrintWriter}
import java.nio.file.{Files, Paths, StandardCopyOption}
 
object Backup extends App {
 
def saveWithBackup(filename: String, data: String*): Unit = { //toRealPath() follows symlinks to their ends
val (file, backFile) = (Paths.get(filename).toRealPath(), new File(filename + ".backup"))
if (!backFile.exists) { // ensure the backup file exists so we can write to it later
backFile.createNewFile
}
val back = Paths.get(filename + ".backup").toRealPath()
Files.move(file, back, StandardCopyOption.REPLACE_EXISTING)
val out = new PrintWriter(file.toFile)
 
for (i <- 0 until data.length) {
out.print(data(i))
if (i < data.length - 1) out.println()
}
}
 
saveWithBackup("original.txt", "fourth", "fifth", "sixth")
 
}</syntaxhighlight>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
proc backupopen {filename mode} {
Line 433 ⟶ 899:
}
return [open $filename $mode]
}</langsyntaxhighlight>
 
=={{header|VBA}}==
<syntaxhighlight lang="vb">Public Sub backup(filename As String)
If Len(Dir(filename)) > 0 Then
On Error Resume Next
Name filename As filename & ".bak"
Else
If Len(Dir(filename & ".lnk")) > 0 Then
On Error Resume Next
With CreateObject("Wscript.Shell").CreateShortcut(filename & ".lnk")
link = .TargetPath
.Close
End With
Name link As link & ".bak"
End If
End If
End Sub
Public Sub main()
backup "D:\test.txt"
End Sub</syntaxhighlight>
 
=={{header|Wren}}==
{{libheader|Wren-ioutil}}
<syntaxhighlight lang="wren">import "./ioutil" for File, FileUtil
 
var saveWithBackup = Fn.new { |filePath, lines|
var origPath = filePath
if (File.exists(origPath)) {
origPath = File.realPath(origPath) // gets the canonical absolute path to the file
var backupPath = origPath + ".backup"
FileUtil.move(origPath, backupPath) // follows Linux convention of moving rather than renaming
}
FileUtil.writeLines(origPath, lines) // overwrites the file if it already exists
}
 
saveWithBackup.call("original.txt", ["fourth", "fifth", "sixth"])
 
// check it worked
System.print("Current contents of original.txt:")
System.print(File.read("original.txt"))
System.print("Contents of original.txt.backup:")
System.print(File.read("original.txt.backup"))</syntaxhighlight>
 
{{out}}
<pre>
Current contents of original.txt:
fourth
fifth
sixth
 
Contents of original.txt.backup:
first
second
third
</pre>
2,122

edits