Питон:Как быстро скопировать файлы [дублировать]

StackOverflow https://stackoverflow.com//questions/22078621

  •  24-12-2019
  •  | 
  •  

Вопрос

Копирование файлов с помощью shutil.copyfile() по сравнению с обычным щелчком правой кнопкой мыши-копировать > щелчок правой кнопкой мыши-вставить с помощью проводника Windows или Finder на Mac.Есть ли какая-нибудь более быстрая альтернатива shutil.copyfile() на Python?Что можно было бы сделать, чтобы ускорить процесс копирования файлов?(Место назначения файлов находится на сетевом диске...если это имеет какое-то значение...).

ОТРЕДАКТИРОВАНО ПОЗЖЕ:

Вот что у меня получилось в итоге:

def copyWithSubprocess(cmd):        
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

win=mac=False
if sys.platform.startswith("darwin"):mac=True
elif sys.platform.startswith("win"):win=True

cmd=None
if mac: cmd=['cp', source, dest]
elif win: cmd=['xcopy', source, dest, '/K/O/X']

if cmd: copyWithSubprocess(cmd)
Это было полезно?

Решение

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

class CTError(Exception):
    def __init__(self, errors):
        self.errors = errors

try:
    O_BINARY = os.O_BINARY
except:
    O_BINARY = 0
READ_FLAGS = os.O_RDONLY | O_BINARY
WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_TRUNC | O_BINARY
BUFFER_SIZE = 128*1024

def copyfile(src, dst):
    try:
        fin = os.open(src, READ_FLAGS)
        stat = os.fstat(fin)
        fout = os.open(dst, WRITE_FLAGS, stat.st_mode)
        for x in iter(lambda: os.read(fin, BUFFER_SIZE), ""):
            os.write(fout, x)
    finally:
        try: os.close(fin)
        except: pass
        try: os.close(fout)
        except: pass

def copytree(src, dst, symlinks=False, ignore=[]):
    names = os.listdir(src)

    if not os.path.exists(dst):
        os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignore:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks, ignore)
            else:
                copyfile(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except (IOError, os.error), why:
            errors.append((srcname, dstname, str(why)))
        except CTError, err:
            errors.extend(err.errors)
    if errors:
        raise CTError(errors)

Этот код выполняется немного медленнее, чем родной linux "cp -rf".

По сравнению с shutil выигрыш для локального хранилища по сравнению с tmfps составляет примерно 2-3 раза, а для NFS по сравнению с локальным хранилищем - около 6 раз.

После профилирования я заметил, что shutil.copy выполняет множество системных функций fstat, которые довольно тяжелы.Если кто-то хочет продолжить оптимизацию, я бы предложил создать единый fstat для src и повторно использовать значения.Честно говоря, я не пошел дальше, так как получил почти те же цифры, что и native linux copy tool, и оптимизация в течение нескольких сотен миллисекунд не была моей целью.

Другие советы

Вы могли бы просто использовать операционную систему, на которой вы выполняете копирование, для Windows:

from subprocess import call
call(["xcopy", "c:\\file.txt", "n:\\folder\\", "/K/O/X"])

/K - Копирует атрибуты.Как правило, Xcopy сбрасывает атрибуты, доступные только для чтения
/O - Копирует информацию о владельце файла и ACL.
/X - Копирует настройки аудита файла (подразумевает /O).

import sys
import subprocess

def copyWithSubprocess(cmd):        
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

cmd=None
if sys.platform.startswith("darwin"): cmd=['cp', source, dest]
elif sys.platform.startswith("win"): cmd=['xcopy', source, dest, '/K/O/X']

if cmd: copyWithSubprocess(cmd)

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

на python

copied_file = open("some_file").read()

является эквивалентом Ctrl + c копировать

затем

with open("new_file","wb") as f:
     f.write(copied_file)

является эквивалентом Ctrl + v вставить (столько раз, чтобы для равномерности....)

если вы хотите, чтобы он был более масштабируемым для больших объемов данных (но это будет не так быстро, как ctrl +v / ctrl +c

with open(infile,"rb") as fin,open(outfile,"wb") as fout:
     fout.writelines(iter(fin.readline,''))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top