patternpythonMinor
A "safe" copy function for Python
Viewed 0 times
functionpythonforsafecopy
Problem
I have a Python script for doing "safe" file copying.
There are a couple of rules for this copy function:
An example use case: I'm importing some camera photos into a folder, but some of the photos may be duplicates (and I don't want two copies) or have the same filename as another photo (and I want to keep both, but small changes to the name aren't important).
```
import filecmp
import os
import shutil
def increment_filename(filename, marker="-"):
"""Appends a counter to a filename, or increments an existing counter."""
basename, fileext = os.path.splitext(filename)
# If there isn't a counter already, then append one
if marker not in basename:
components = [basename, 1, fileext]
# If it looks like there might be a counter, then try to coerce it to an
# integer and increment it. If that fails, then just append a new counter.
else:
base, counter = basename.rsplit(marker, 1)
try:
new_counter = int(counter) + 1
components = [base, new_counter, fileext]
except ValueError:
components = [base, 1, fileext]
# Drop in the marker before the counter
components.insert(1, marker)
new_filename = "%s%s%d%s" % tuple(components)
return new_filename
def copyfile(src, dst):
"""Copies a file from path src to path dst.
If a file already exists at dst, it will not be overwritten, bu
There are a couple of rules for this copy function:
- Existing files should never be overwritten. So if I try to copy
$file1to$location, and there is already$file2at$location, then$file2will not be overwritten.
- Exact filenames are not important. So if I try to copy a file to
$location.txt, and because there’s already a different file there, it instead gets copied to$location-1.txt, that’s okay.
- Copying should be idempotent. That is, if I try to copy a file to
$location, and it's already there, nothing else happens. I'm not going to create more copies at$location-1,$location-2,$location-3, etc.
An example use case: I'm importing some camera photos into a folder, but some of the photos may be duplicates (and I don't want two copies) or have the same filename as another photo (and I want to keep both, but small changes to the name aren't important).
```
import filecmp
import os
import shutil
def increment_filename(filename, marker="-"):
"""Appends a counter to a filename, or increments an existing counter."""
basename, fileext = os.path.splitext(filename)
# If there isn't a counter already, then append one
if marker not in basename:
components = [basename, 1, fileext]
# If it looks like there might be a counter, then try to coerce it to an
# integer and increment it. If that fails, then just append a new counter.
else:
base, counter = basename.rsplit(marker, 1)
try:
new_counter = int(counter) + 1
components = [base, new_counter, fileext]
except ValueError:
components = [base, 1, fileext]
# Drop in the marker before the counter
components.insert(1, marker)
new_filename = "%s%s%d%s" % tuple(components)
return new_filename
def copyfile(src, dst):
"""Copies a file from path src to path dst.
If a file already exists at dst, it will not be overwritten, bu
Solution
As the documentation for
If
You have attempted to work around that by checking
A way to ensure that you do not overwrite an existing file is to use
shutil.copyfile(src, dst) says,If
dst already exists, it will be replaced.You have attempted to work around that by checking
if not os.path.exists(dst) first. However, that logic is vulnerable to a race condition if the destination file springs into existence just after the check.A way to ensure that you do not overwrite an existing file is to use
os.open() with the os.O_EXCL flag. You would need to write the read-write loop yourself to transfer the file contents, but that is not difficult.Context
StackExchange Code Review Q#89985, answer score: 5
Revisions (0)
No revisions yet.