Python - перемещать и перезаписывать файлы и папки - PullRequest
62 голосов
/ 14 сентября 2011

У меня есть каталог 'Dst Directory', в котором есть файлы и папки, и у меня есть 'src Directory', в котором также есть файлы и папки. Я хочу переместить содержимое 'src Directory' в 'Dst Directory' и перезаписать любые файлы, которые существуют с таким же именем. Так, например, «Src Directory \ file.txt» необходимо переместить в «Dst Directory \» и перезаписать существующий файл «file.txt». То же самое относится к некоторым папкам, перемещая папку и объединяя содержимое с той же папкой в ​​«dst directory»

В настоящее время я использую shutil.move для перемещения содержимого src в dst, но он не сделает этого, если файлы уже существуют, и не объединит папки; он просто поместит папку в существующую папку.

Обновление: чтобы сделать вещи немного яснее; То, что я делаю, - это разархивирование архива в Dst Directory, а затем перемещение туда содержимого Src Directory и повторное архивирование, эффективное обновление файлов в zip-архиве. Это будет повторяться для добавления новых файлов или новых версий файлов и т. Д., Поэтому необходимо перезаписать и объединить

Решено: я решил свою проблему с помощью distutils.dir_util.copy_tree (src, dst), он копирует папки и файлы из каталога src в каталог dst и перезаписывает / объединяет в случае необходимости. Надеюсь, что это поможет некоторым людям!

Надеюсь, это имеет смысл, спасибо!

Ответы [ 6 ]

52 голосов
/ 14 сентября 2011

Это будет проходить через исходный каталог, создавать любые каталоги, которые еще не существуют в целевом каталоге, и перемещать файлы из исходного каталога в целевой каталог:

import os
import shutil

root_src_dir = 'Src Directory\\'
root_dst_dir = 'Dst Directory\\'

for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            # in case of the src and dst are the same file
            if os.path.samefile(src_file, dst_file):
                continue
            os.remove(dst_file)
        shutil.move(src_file, dst_dir)

Все ранее существующие файлы будут удаленысначала (через os.remove) перед заменой на соответствующий исходный файл.Любые файлы или каталоги, которые уже существуют в месте назначения, но отсутствуют в источнике, останутся нетронутыми.

45 голосов
/ 14 сентября 2011

Вместо этого используйте copy(), который готов перезаписать файлы назначения. Если вы хотите, чтобы первое дерево исчезло, просто rmtree() отдельно, как только вы закончите его итерацию.

http://docs.python.org/library/shutil.html#shutil.copy

http://docs.python.org/library/shutil.html#shutil.rmtree

Обновление:

Сделайте os.walk() над исходным деревом. Для каждого каталога проверьте, существует ли он на стороне назначения, и os.makedirs(), если он отсутствует. Для каждого файла просто shutil.copy(), и файл будет создан или перезаписан, в зависимости от того, что подходит.

6 голосов
/ 10 октября 2014

Поскольку ничего из вышеперечисленного не помогло мне, я написал свою рекурсивную функцию Вызовите функцию copyTree (dir1, dir2) для объединения каталогов. Работать на мультиплатформенных Linux и Windows.

def forceMergeFlatDir(srcDir, dstDir):
    if not os.path.exists(dstDir):
        os.makedirs(dstDir)
    for item in os.listdir(srcDir):
        srcFile = os.path.join(srcDir, item)
        dstFile = os.path.join(dstDir, item)
        forceCopyFile(srcFile, dstFile)

def forceCopyFile (sfile, dfile):
    if os.path.isfile(sfile):
        shutil.copy2(sfile, dfile)

def isAFlatDir(sDir):
    for item in os.listdir(sDir):
        sItem = os.path.join(sDir, item)
        if os.path.isdir(sItem):
            return False
    return True


def copyTree(src, dst):
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isfile(s):
            if not os.path.exists(dst):
                os.makedirs(dst)
            forceCopyFile(s,d)
        if os.path.isdir(s):
            isRecursive = not isAFlatDir(s)
            if isRecursive:
                copyTree(s, d)
            else:
                forceMergeFlatDir(s, d)
4 голосов
/ 20 апреля 2017

Если вам также нужно перезаписать файлы с флагом только для чтения, используйте это:

def copyDirTree(root_src_dir,root_dst_dir):
"""
Copy directory tree. Overwrites also read only files.
:param root_src_dir: source directory
:param root_dst_dir:  destination directory
"""
for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            try:
                os.remove(dst_file)
            except PermissionError as exc:
                os.chmod(dst_file, stat.S_IWUSR)
                os.remove(dst_file)

        shutil.copy(src_file, dst_dir)
1 голос
/ 14 сентября 2011

Посмотрите: os.remove, чтобы удалить существующие файлы.

0 голосов
/ 20 апреля 2015

У меня была похожая проблема. Я хотел переместить файлы и структуры папок и перезаписать существующие файлы, но не удалить ничего, что находится в структуре папок назначения.

Я решил это, используя os.walk(), рекурсивно вызывая свою функцию и используя shutil.move() для файлов, которые я хотел перезаписать, и папок, которых не было.

Он работает как shutil.move(), но с тем преимуществом, что существующие файлы только перезаписываются, но не удаляются.

import os
import shutil

def moverecursively(source_folder, destination_folder):
    basename = os.path.basename(source_folder)
    dest_dir = os.path.join(destination_folder, basename)
    if not os.path.exists(dest_dir):
        shutil.move(source_folder, destination_folder)
    else:
        dst_path = os.path.join(destination_folder, basename)
        for root, dirs, files in os.walk(source_folder):
            for item in files:
                src_path = os.path.join(root, item)
                if os.path.exists(dst_file):
                    os.remove(dst_file)
                shutil.move(src_path, dst_path)
            for item in dirs:
                src_path = os.path.join(root, item)
                moverecursively(src_path, dst_path)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...