Питон:Как быстро скопировать файлы [дублировать]
-
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,''))