Since the \\?\
prefix bypasses normal path processing, the path needs to be absolute, can only use backslash as the path separator, and has to be a UTF-16 string. In Python 2, use the u
prefix to create a unicode
string (UTF-16 on Windows).
shutil.copyfile
opens the source file in 'rb'
mode and destination file in 'wb'
mode, and then copies from source to destination in 16 KiB chunks. Given a unicode
path, Python 2 opens a file by calling the C runtime function _wfopen
, which in turn calls the Windows wide-character API CreateFileW
.
shutil.copyfile
should work with long paths, assuming they're correctly formatted. If it's not working for you, I can't think of any way to "force" it to work.
Here's a Python 2 example that creates a 10-level tree of directories, each named u'a' * 255
, and copies a file from the working directory into the leaf of the tree. The destination path is about 2600 characters, depending on your working directory.
#!python2
import os
import shutil
work = 'longpath_work'
if not os.path.exists(work):
os.mkdir(work)
os.chdir(work)
# create a text file to copy
if not os.path.exists('spam.txt'):
with open('spam.txt', 'w') as f:
f.write('spam spam spam')
# create 10-level tree of directories
name = u'a' * 255
base = u'\\'.join([u'\\\\?', os.getcwd(), name])
if os.path.exists(base):
shutil.rmtree(base)
rest = u'\\'.join([name] * 9)
path = u'\\'.join([base, rest])
os.makedirs(path)
print 'src directory listing (tree created)'
print os.listdir(u'.')
dest = u'\\'.join([path, u'spam.txt'])
shutil.copyfile(u'spam.txt', dest)
print '\ndest directory listing'
print os.listdir(path)
print '\ncopied file contents'
with open(dest) as f:
print f.read()
# Remove the tree, and verify that it's removed:
shutil.rmtree(base)
print '\nsrc directory listing (tree removed)'
print os.listdir(u'.')
Output (line wrapped):
src directory listing (tree created)
[u'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa', u'spam.txt']
dest directory listing
[u'spam.txt']
copied file contents
spam spam spam
src directory listing (tree removed)
[u'spam.txt']