В чем разница между копией и копировальным файлом?
Мэтт
389
в копии (src, dst) dst может быть каталогом.
Оуэн
41
Обратите внимание, что не все метаданные будут скопированы, в зависимости от вашей платформы.
Кевин Хорн
12
Обратите внимание, что это не атомарная операция. Будьте осторожны, используя его в резьбовом приложении.
waterbyte
4
Обратите внимание, что он не может обрабатывать такие сокращения, как ~, но он может иметь дело с относительными путями
zwep
1256
┌──────────────────┬────────┬───────────┬───────┬────────────────┐
│ Function │ Copies │ Copies │Can use│ Destination │
│ │metadata│permissions│buffer │may be directory│
├──────────────────┼────────┼───────────┼───────┼────────────────┤
│shutil.copy │ No │ Yes │ No │ Yes │
│shutil.copyfile │ No │ No │ No │ No │
│shutil.copy2 │ Yes │ Yes │ No │ Yes │
│shutil.copyfileobj│ No │ No │ Yes │ No │
└──────────────────┴────────┴───────────┴───────┴────────────────┘
Я пытаюсь случайным образом скопировать 100 000 файлов из 1 миллиона файлов. copyfileзначительно быстрее, чемcopy2
Виджей
4
правильно ли я предположить, что shutil.copy2('/dir/file.ext', '/new/dir/')(с косой чертой после целевого пути) удалит неоднозначность в отношении того, копировать ли в новый файл с именем «dir» или поместить файл в каталог с таким именем?
Зак
1
@ Виджай Я считаю, что это связано с копированием метаданных.
Джонатан Х
@Zak Нет никакой двусмысленности, если /new/dirсуществует существующий каталог, см. Комментарий @ MatthewAlpert.
Джонатан Х
@Zak Вы правы, добавление косой черты в конец устраняет неоднозначность. Если /new/dir/он не существует, Python сгенерирует IsADirectoryError, в противном случае он копирует файл с /new/dir/исходным именем.
martonbognar
125
Вы можете использовать одну из функций копирования из shutilпакета:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Функция сохраняет поддерживает принимает копии других
каталог разрешений dest. метаданные файла obj
-------------------------------------------------- ----------------------------
shutil.copy ☐ ✔ ☐ ☐
shutil.copy2 ✔ ✔ ☐ ✔
shutil.copyfile ☐ ☐ ☐ ☐
shutil.copyfileobj ☐ ☐ ✔ ☐
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@lightalchemist Я просто использовал vim в качестве блокнота, скопировал использованные символы юникода из таблицы википедии и скопировал результат в редактор стека переполнения для окончательной полировки.
@wim, вы должны сравнить мой ответ с версией ответа 2017 года, которую вы связали, которая была актуальна, когда я опубликовал свой ответ. Основные отличия: в моем ответе используются более качественные / более описательные заголовки столбцов, макет таблицы не отвлекает, он включает прямые ссылки в документацию, и я добавил столбец (т.е. «принимает файл obj»).
maxschlepzig
4
ХОРОШО. YMMV, но я думаю, что косметические изменения и подобные мелкие улучшения лучше вносить в виде правок существующих ответов, а не дублирования ответов.
os.popen(cmd[, mode[, bufsize]])# example# In Unix/Linux
os.popen('cp source.txt destination.txt')# In Windows
os.popen('copy source.txt destination.txt')
subprocess.call(args,*, stdin=None, stdout=None, stderr=None, shell=False)# example (WARNING: setting `shell=True` might be a security-risk)# In Linux/Unix
status = subprocess.call('cp source.txt destination.txt', shell=True)# In Windows
status = subprocess.call('copy source.txt destination.txt', shell=True)
subprocess.check_output(args,*, stdin=None, stderr=None, shell=False, universal_newlines=False)# example (WARNING: setting `shell=True` might be a security-risk)# In Linux/Unix
status = subprocess.check_output('cp source.txt destination.txt', shell=True)# In Windows
status = subprocess.check_output('copy source.txt destination.txt', shell=True)
Использование однострочных команд - плохой стиль кодирования (гибкость, надежность и безопасность), вместо этого используйте ['copy', sourcefile, destfile]везде, где это возможно, синтаксис, особенно если параметры получены из пользовательского ввода.
Марсель Вальдвогель
8
Почему вы перечисляете так много плохих альтернатив функциям копирования shutil?
maxschlepzig
6
Шутил встроен, нет необходимости предоставлять непереносимые альтернативы. Ответ может быть фактически улучшен путем удаления системно-зависимых решений, и после этого удаления этот ответ является просто копией существующих ответов / копией документации.
Жан-Франсуа Фабр
3
os.popenна некоторое время устарела. и check_outputне возвращает статус, но вывод (который пустой в случае copy/cp)
Жан-Франсуа Фабр
2
Шутил на самом деле не копирует файлы. Есть большое толстое предупреждение прямо наверху документов . «Это означает, что владелец файла и группа будут потеряны, а также ACL. В Mac OS не используются ветвь ресурса и другие метаданные. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки ACL и альтернативные потоки данных не копируются ».
Человек
96
Копирование файла является относительно простой операцией, как показано в примерах ниже, но вместо этого вам следует использовать модуль shutil stdlib .
def copyfileobj_example(source, dest, buffer_size=1024*1024):"""
Copy a file from source to dest. source and dest
must be file-like objects, i.e. any object with a read or
write method, like for example StringIO.
"""whileTrue:
copy_buffer = source.read(buffer_size)ifnot copy_buffer:break
dest.write(copy_buffer)
Если вы хотите скопировать по имени файла, вы можете сделать что-то вроде этого:
def copyfile_example(source, dest):# Beware, this example does not handle any edge cases!with open(source,'rb')as src, open(dest,'wb')as dst:
copyfileobj_example(src, dst)
Некоторое время назад я заметил, что модуль называется shutil (единственное число), а не shutils (множественное число), и действительно он есть в Python 2.3. Тем не менее я оставляю эту функцию здесь в качестве примера.
пи.
4
Копирование содержимого файла является простой операцией. Копировать файл с его метаданными совсем не просто, особенно если вы хотите быть кроссплатформенным.
LaC
3
Правда. Глядя на документы shutil, функция copyfile также не будет копировать метаданные.
пи.
3
Да, я не уверен, почему бы вам не скопировать источник shutil.copyfileobj. Кроме того, вам не нужно try, finallyобрабатывать закрытие файлов после исключений. Однако я бы сказал, что ваша функция вообще не должна отвечать за открытие и закрытие файлов. Это должно идти в функции-обертке, например, как shutil.copyfileобертки shutil.copyfileobj.
ErlVolton
2
Приведенный выше код должен destбыть указан для записи:open(dest, 'wb')
Скопируйте содержимое файла с именем src в файл с именем dst. Место назначения должно быть доступно для записи; в противном случае возникнет исключение IOError. Если dst уже существует, он будет заменен. Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции. src и dst - это имена путей, заданные в виде строк.
Посмотрите на filesys все функции обработки файлов и каталогов, доступные в стандартных модулях Python.
Шутил на самом деле не копирует файлы. Есть большое толстое предупреждение прямо наверху документов . «Это означает, что владелец файла и группа будут потеряны, а также ACL. В Mac OS не используются ветвь ресурса и другие метаданные. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки ACL и альтернативные потоки данных не копируются ».
Человек
47
Пример копирования каталога и файла - Из материала Питона Тима Голдена:
Шутил на самом деле не копирует файлы. Есть большое толстое предупреждение прямо наверху документов . «Это означает, что владелец файла и группа будут потеряны, а также ACL. В Mac OS не используются ветвь ресурса и другие метаданные. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки ACL и альтернативные потоки данных не копируются ».
Человек
19
Для небольших файлов и использования только встроенных Python, вы можете использовать следующую однострочную:
with open(source,'rb')as src, open(dest,'wb')as dst: dst.write(src.read())
Как @maxschlepzig упомянул в комментариях ниже, это не оптимальный способ для приложений, где файл слишком велик или когда память критична, поэтому ответ Свати должен быть предпочтительным.
Это читает весь исходный файл в память, прежде чем записать его обратно. Таким образом, это излишне тратит впустую память для всех, кроме самых маленьких операций копирования файла.
maxschlepzig
1
Это правда? Я думаю .read()и .write()буферизируются по умолчанию (по крайней мере для CPython).
soundstripe
@soundstripe, конечно, это правда. Тот факт, что объект file, возвращаемый с помощью open()буферизированного ввода-вывода, по умолчанию здесь не помогает, поскольку read()он указан как: «Если n отрицательно или опущено, читайте до EOF». Это означает, что read()возвращает полное содержимое файла в виде строки.
maxschlepzig
@maxschlepzig Я понял вашу точку зрения и признаюсь, что не знал об этом. Причина, по которой я дал этот ответ, заключалась в том, что кто-то хотел сделать простую копию файла, используя только встроенные модули, без необходимости импортировать для него модуль. Конечно, оптимизация памяти не должна беспокоить, если вы хотите эту опцию. В любом случае, спасибо, что очистили это. Я обновил ответ соответственно.
yellow01
14
Вы могли бы использовать os.system('cp nameoffilegeneratedbyprogram /otherdirectory/')
или как я это сделал,
os.system('cp '+ rawfile +' rawdata.dat')
где rawfileэто имя, которое я сгенерировал внутри программы.
это не переносимо и не нужно, так как вы можете просто использовать shutil.
Кори Голдберг
4
Даже когда shutilнет в наличии - subprocess.run() (без shell=True!) Лучшая альтернатива os.system().
maxschlepzig
1
Шутиль более портативен
Hiadore
1
subprocess.run()как подсказывает @maxschlepzig, это большой шаг вперед при вызове внешних программ. Однако для гибкости и безопасности используйте ['cp', rawfile, 'rawdata.dat']форму передачи командной строки. (Однако для копирования shutilрекомендуется и друзьям вызывать внешнюю программу.)
Марсель Вальдвогель
2
попробуйте это с именами файлов с пробелами в нем.
Жан-Франсуа Фабр
11
Для больших файлов я построчно считывал файл и читал каждую строку в массив. Затем, когда массив достигнет определенного размера, добавьте его в новый файл.
for line in open("file.txt","r"):
list.append(line)if len(list)==1000000:
output.writelines(list)del list[:]
это кажется немного излишним, так как писатель должен обрабатывать буферизацию. for l in open('file.txt','r'): output.write(l)должен работать найти; просто настройте буфер потока вывода в соответствии с вашими потребностями. или вы можете переходить по байтам, повторяя попытку, output.write(read(n)); output.flush()где nуказано количество байтов, которое вы хотите записать за раз. оба из них также не имеют условия, чтобы проверить, что является бонусом.
владеет
1
Да, но я подумал, что, возможно, это будет легче понять, потому что он копирует целые строки, а не их части (в случае, если мы не знаем, сколько байтов каждая строка).
ytpillai
Очень верно. Кодирование для обучения и кодирование для эффективности очень разные.
Это ужасно Это делает ненужную работу без уважительной причины. Это не работает для произвольных файлов. Копия не идентична байту, если ввод имеет необычные окончания строк в таких системах, как Windows. Почему вы думаете, что это может быть легче понять, чем вызов функции копирования в shutil? Даже при игнорировании shutilпростой цикл чтения / записи блока (с использованием небуферизованного ввода-вывода) является простым, эффективным и имеет гораздо больший смысл, чем этот, и, следовательно, его легче учить и понимать.
maxschlepzig
11
from subprocess import call
call("cp -p <file> <file>", shell=True)
И затем кто-то использует код (случайно или целенаправленно) для большого файла ... Использование функций из них shutilобрабатывает все особые случаи для вас и дает вам душевное спокойствие.
Марсель Вальдвогель,
4
по крайней мере, это не повторяет одни и те же решения снова и снова.
Идея хороша, а код красив, но правильная функция copy () может делать больше вещей, таких как копирование атрибутов (+ x бит) или, например, удаление уже скопированных байтов в случае, если найдено условие переполнения диска ,
Рауль Салинас-Монтеагудо
1
Все ответы требуют объяснения, даже если это одно предложение. Никакие объяснения не создают плохой прецедент и не помогают понять программу. Что если полный нуб Python придет и увидит это, захочет его использовать, но не сможет, потому что они этого не понимают? Вы хотите быть полезными для всех в своих ответах.
connectyourcharger
1
Разве это не скучает .close()по всем этим open(...)с?
luckydonald
Нет необходимости в .close (), поскольку мы нигде не храним объект указателя файла (ни для файла src, ни для файла назначения).
Ответы:
shutil
Есть много методов, которые вы можете использовать. Одним из которых является:Если вы используете
os.path
операции, используйте,copy
а неcopyfile
.copyfile
будет принимать только строки .источник
~
, но он может иметь дело с относительными путямиисточник
copy2(src,dst)
часто более полезен, чемcopyfile(src,dst)
потому что:dst
быть каталог (вместо полного целевого файла), в этом случае базовый изsrc
используются для создания нового файла;Вот краткий пример:
источник
copyfile
значительно быстрее, чемcopy2
shutil.copy2('/dir/file.ext', '/new/dir/')
(с косой чертой после целевого пути) удалит неоднозначность в отношении того, копировать ли в новый файл с именем «dir» или поместить файл в каталог с таким именем?/new/dir
существует существующий каталог, см. Комментарий @ MatthewAlpert./new/dir/
он не существует, Python сгенерируетIsADirectoryError
, в противном случае он копирует файл с/new/dir/
исходным именем.Вы можете использовать одну из функций копирования из
shutil
пакета:Пример:
источник
В Python вы можете скопировать файлы, используя
shutil
модульos
модульsubprocess
модуль1) Копирование файлов с использованием
shutil
модуляshutil.copyfile
подписьshutil.copy
подписьshutil.copy2
подписьshutil.copyfileobj
подпись2) Копирование файлов с использованием
os
модуляos.popen
подписьos.system
подпись3) Копирование файлов с использованием
subprocess
модуляsubprocess.call
подписьsubprocess.check_output
подписьисточник
['copy', sourcefile, destfile]
везде, где это возможно, синтаксис, особенно если параметры получены из пользовательского ввода.os.popen
на некоторое время устарела. иcheck_output
не возвращает статус, но вывод (который пустой в случаеcopy/cp
)Копирование файла является относительно простой операцией, как показано в примерах ниже, но вместо этого вам следует использовать модуль shutil stdlib .
Если вы хотите скопировать по имени файла, вы можете сделать что-то вроде этого:
источник
shutil.copyfileobj
. Кроме того, вам не нужноtry, finally
обрабатывать закрытие файлов после исключений. Однако я бы сказал, что ваша функция вообще не должна отвечать за открытие и закрытие файлов. Это должно идти в функции-обертке, например, какshutil.copyfile
оберткиshutil.copyfileobj
.dest
быть указан для записи:open(dest, 'wb')
Используйте модуль shutil .
Скопируйте содержимое файла с именем src в файл с именем dst. Место назначения должно быть доступно для записи; в противном случае возникнет исключение IOError. Если dst уже существует, он будет заменен. Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции. src и dst - это имена путей, заданные в виде строк.
Посмотрите на filesys все функции обработки файлов и каталогов, доступные в стандартных модулях Python.
источник
Пример копирования каталога и файла - Из материала Питона Тима Голдена:
http://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html
источник
Во-первых, я сделал исчерпывающую таблицу методов шутиля для вашей справки.
Во-вторых, объясните методы копирования в exmaples:
Рекурсивно скопировать все дерево каталогов с корнем в src, возвращая каталог назначения
источник
Для небольших файлов и использования только встроенных Python, вы можете использовать следующую однострочную:
Как @maxschlepzig упомянул в комментариях ниже, это не оптимальный способ для приложений, где файл слишком велик или когда память критична, поэтому ответ Свати должен быть предпочтительным.
источник
.read()
и.write()
буферизируются по умолчанию (по крайней мере для CPython).open()
буферизированного ввода-вывода, по умолчанию здесь не помогает, посколькуread()
он указан как: «Если n отрицательно или опущено, читайте до EOF». Это означает, чтоread()
возвращает полное содержимое файла в виде строки.Вы могли бы использовать
os.system('cp nameoffilegeneratedbyprogram /otherdirectory/')
или как я это сделал,
где
rawfile
это имя, которое я сгенерировал внутри программы.Это решение только для Linux
источник
shutil
нет в наличии -subprocess.run()
(безshell=True
!) Лучшая альтернативаos.system()
.subprocess.run()
как подсказывает @maxschlepzig, это большой шаг вперед при вызове внешних программ. Однако для гибкости и безопасности используйте['cp', rawfile, 'rawdata.dat']
форму передачи командной строки. (Однако для копированияshutil
рекомендуется и друзьям вызывать внешнюю программу.)Для больших файлов я построчно считывал файл и читал каждую строку в массив. Затем, когда массив достигнет определенного размера, добавьте его в новый файл.
источник
for l in open('file.txt','r'): output.write(l)
должен работать найти; просто настройте буфер потока вывода в соответствии с вашими потребностями. или вы можете переходить по байтам, повторяя попытку,output.write(read(n)); output.flush()
гдеn
указано количество байтов, которое вы хотите записать за раз. оба из них также не имеют условия, чтобы проверить, что является бонусом.shutil
? Даже при игнорированииshutil
простой цикл чтения / записи блока (с использованием небуферизованного ввода-вывода) является простым, эффективным и имеет гораздо больший смысл, чем этот, и, следовательно, его легче учить и понимать.источник
call
небезопасно. Пожалуйста, обратитесь к документу subproces об этом.Начиная с Python 3.5 вы можете делать следующее для небольших файлов (например: текстовые файлы, маленькие JPEG):
write_bytes
перезапишет все, что было в месте назначенияисточник
shutil
обрабатывает все особые случаи для вас и дает вам душевное спокойствие.Откройте исходный файл в режиме чтения и запишите в целевой файл в режиме записи.
источник
.close()
по всем этимopen(...)
с?Python предоставляет встроенные функции для простого копирования файлов с помощью утилит операционной системы.
Следующая команда используется для копирования файла
Следующая команда используется для копирования файла с информацией метаданных
источник
copy
Затем вы должны запустить,copystat
чтобы сохранить метаданные файла. В Python 3.3+copystat
также копируются расширенные атрибуты.