我需要将目录从一个位置移动到同一文件系统上的另一个位置。我知道类似的解决方案shutil.move(),但是有问题的文件系统是 SD 卡(因此非常慢),并且有很多文件要移动,所以简单地复制它们然后删除原件是不可接受的。Unixmv命令可以将目录从一个文件系统移动到同一个文件系统,而无需复制任何文件——有没有办法在 Python 中做到这一点?
1 回答
0
事实证明,答案是肯定的。您可能知道,您可以使用os.rename(r'D:\path1\myfile.txt', r'D:\path2\myfile.txt'). 您可以对目录执行相同的操作:
os.rename(r'D:\long\path\to\mydir', r'D:\mydir')
但是,当然,只有在 D:\mydir 尚不存在时才有效。如果它确实存在,并且您想将已经存在的文件与您正在移动的文件合并,那么您需要变得更聪明一些。这是一个片段,可以做你想做的事:
def movedir(src, dst):
try:
os.rename(src, dst)
return
except FileExistsError:
pass
for root, dirs, files in os.walk(src):
dest_root = os.path.join(dst, os.path.relpath(root, src))
done = []
for dir_ in dirs:
try:
os.rename(os.path.join(root, dir_), os.path.join(dest_root, dir_))
done.append(dir_)
except FileExistsError:
pass
for dir_ in done:
dirs.remove(dir_)
for file in files:
os.replace(os.path.join(root, file), os.path.join(dest_root, file))
for root, dirs, files in os.walk(src, topdown=False):
os.rmdir(root)
这是一个带有注释的版本,解释了一切的作用:
def movedir(src, dst):
# if a directory of the same name does not exist in the destination, we can simply rename the directory
# to a different path, and it will be moved -- it will disappear from the source path and appear in the destination
# path instantaneously, without any files being copied.
try:
os.rename(src, dst)
return
except FileExistsError:
# if a directory of the same name already exists, we must merge them. This is what the algorithm below does.
pass
for root, dirs, files in os.walk(src):
dest_root = os.path.join(dst, os.path.relpath(root, src))
done = []
for dir_ in dirs:
try:
os.rename(os.path.join(root, dir_), os.path.join(dest_root, dir_))
done.append(dir_)
except FileExistsError:
pass
# tell os.walk() not to recurse into subdirectories we've already moved. see the documentation on os.walk()
# for why this works: https://docs.python.org/3/library/os.html#os.walk
# lists can't be modified during iteration, so we have to put all the items we want to remove from the list
# into a second list, and then remove them after the loop.
for dir_ in done:
dirs.remove(dir_)
# move files. os.replace() is a bit like os.rename() but if there's an existing file in the destination with
# the same name, it will be deleted and replaced with the source file without prompting the user. It doesn't
# work on directories, so we only use it for files.
# You may want to change this to os.rename() and surround it with a try/except FileExistsError if you
# want to prompt the user to overwrite files.
for file in files:
os.replace(os.path.join(root, file), os.path.join(dest_root, file))
# clean up after ourselves.
# Directories we were able to successfully move just by renaming them (directories that didn't exist in the
# destination already) have already disappeared from the source. Directories we had to merge are still there in
# the source, but their contents were moved. os.rmdir() will fail unless the directory is already empty.
for root, dirs, files in os.walk(src, topdown=False):
os.rmdir(root)
movedir(r'D:\long\path\to\mydir', r'D:\mydir')
请注意,以这种方式使用 os.rename() 仅在源路径和目标路径位于同一文件系统上时才有效(在 Windows 上,如果它们具有相同的驱动器号,则为真)。如果它们位于不同的驱动器号上(即一个在 C: 上,另一个在 D: 上)或者其中一个路径包含重解析点(如果您不知道那是什么,请不要担心,您可能永远不会遇到一个),您将需要使用shutil.move(),它复制文件然后从源中删除它们 - 这是 Windows 在驱动器之间移动文件时所做的事情,并且完成所需的时间大约一样长。
于 2021-04-13T23:36:47.360 回答