fcount, dcount = copytree(*dirstuple)
print('Copied', fcount, 'files,', dcount, 'directories', end=' ')
print('in', time.clock() - start, 'seconds')
This script implements its own recursive tree traversal logic and keeps track of both
the “from” and “to” directory paths as it goes. At every level, it copies over simple files,
creates directories in the “to” path, and recurs into subdirectories with “from” and “to”
paths extended by one level. There are other ways to code this task (e.g., we might
change the working directory along the way with os.chdir calls or there is probably an
os.walk solution which replaces from and to path prefixes as it walks), but extending
paths on recursive descent works well in this script.
Notice this script’s reusable copyfile function—just in case there are multigigabyte
files in the tree to be copied, it uses a file’s size to decide whether it should be read all
at once or in chunks (remember, the file read method without arguments actually loads
the entire file into an in-memory string). We choose fairly large file and block sizes,
because the more we read at once in Python, the faster our scripts will typically run.
This is more efficient than it may sound; strings left behind by prior reads will be
garbage collected and reused as we go. We’re using binary file modes here again, too,
to suppress the Unicode encodings and end-of-line translations of text files—trees may
contain arbitrary kinds of files.
Also notice that this script creates the “to” directory if needed, but it assumes that the
directory is empty when a copy starts up; for accuracy, be sure to remove the target
directory before copying a new tree to its name, or old files may linger in the target tree
(we could automatically remove the target first, but this may not always be desired).
This script also tries to determine if the source and target are the same; on Unix-like
platforms with oddities such as links, os.path.samefile does a more accurate job than
comparing absolute file names (different file names may be the same file).
Here is a copy of a big book examples tree (I use the tree from the prior edition
throughout this chapter) in action on Windows; pass in the name of the “from” and
“to” directories to kick off the process, redirect the output to a file if there are too many
error messages to read all at once (e.g., > output.txt), and run an rm –r or rmdir /S
shell command (or similar platform-specific tool) to delete the target directory first if
needed:
C:\...\PP4E\System\Filetools> rmdir /S copytemp
copytemp, Are you sure (Y/N)? y
C:\...\PP4E\System\Filetools> cpall.py C:\temp\PP3E\Examples copytemp
Note: dirTo was created
Copying...
Copied 1430 files, 185 directories in 10.4470980971 seconds
C:\...\PP4E\System\Filetools> fc /B copytemp\PP3E\Launcher.py
C:\temp\PP3E\Examples\PP3E\Launcher.py
Comparing files COPYTEMP\PP3E\Launcher.py and C:\TEMP\PP3E\EXAMPLES\PP3E\LAUNCHER.PY
FC: no differences encountered
Copying Directory Trees | 307