Welcome, guest | Sign In | My Account | Store | Cart

If the specified file exists, it is versioned by appending to the extension a three-digit number, starting with "000".

Python, 36 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def VersionFile(file_spec, vtype='copy'):
	import os, shutil

	ok = 0
	if os.path.isfile(file_spec):
		# or do other error checking...
		if vtype not in ('copy', 'rename'):
			vtype = 'copy'

		# determine root file name so the extension doesn't get longer and longer...
		n, e = os.path.splitext(file_spec)

		# is e an integer?
		try:
			num = int(e)
			root = n
		except ValueError:
			root = file_spec

		# find next available file version
		for i in xrange(1000):
			new_file = '%s.%03d' % (root, i)
			if not os.path.isfile(new_file):
				if vtype == 'copy':
					shutil.copy(file_spec, new_file)
				else:
					os.rename(file_spec, new_file)
				ok = 1
				break
	return ok

if __name__ == '__main__':
	# test code (you will need a file named test.txt)
	print VersionFile('test.txt')
	print VersionFile('test.txt')
	print VersionFile('test.txt')

It's polite to make backups of files before you mangle them. A standard way of doing so is to appending to the extension an incremented number. The optional second parameter allows you to specify whether the original file will be copied (the default) or renamed.

Limitation: after 1000 versions you're sunk. Better have an archive plan <grin>.

1 comment

Martin Miller 17 years, 5 months ago  # | flag

Bug. The code to detect and handle numeric extensions, namely the:

&gt; # is e an integer?
&gt; try:
&gt;         num = int(e)
&gt;         root = n
&gt; except ValueError:
&gt;         root = file_spec

will not work because if the file name does have an extension, after the os.path.splitext() call the variable 'e' will contain a string that starts with a period.

Because of that fact, the int(e) expression will always raise an exception, in which case the entire file name will be assigned to varible 'root'. After this happens the renamed file would have another three-digit extension added to it each time this function is called.