Как мне скопировать файл в Python?

2481

Как мне скопировать файл в Python?

Я не мог найти ничего под os.

Matt
источник
117
Кажется, что cp не является системным вызовом и поэтому не принадлежит модулю os. Это команда оболочки, поэтому она помещается в модуль shutil.
waldol1

Ответы:

3016

shutilЕсть много методов, которые вы можете использовать. Одним из которых является:

from shutil import copyfile
copyfile(src, dst)
  • Скопируйте содержимое файла с именем src в файл с именем dst .
  • Место назначения должно быть доступно для записи; в противном случае возникнет исключение IOError .
  • Если dst уже существует, он будет заменен.
  • Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции.
  • С копией , СРК и целевой_адрес имена путей , приведенные в строках .

Если вы используете os.pathоперации, используйте, copyа не copyfile. copyfileбудет принимать только строки .

Свати
источник
147
В чем разница между копией и копировальным файлом?
Мэтт
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       │
└──────────────────┴────────┴───────────┴───────┴────────────────┘
jezrael
источник
733

copy2(src,dst)часто более полезен, чем copyfile(src,dst)потому что:

  • это позволяет dstбыть каталог (вместо полного целевого файла), в этом случае базовый из srcиспользуются для создания нового файла;
  • он сохраняет исходную информацию о модификации и доступе (mtime и atime) в метаданных файла (однако это идет с небольшими издержками).

Вот краткий пример:

import shutil
shutil.copy2('/src/dir/file.ext', '/dst/dir/newname.ext') # complete target filename given
shutil.copy2('/src/file.ext', '/dst/dir') # target filename is /dst/dir/file.ext
неокантованный
источник
19
Я пытаюсь случайным образом скопировать 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        ☐ ☐ ✔ ☐
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Пример:

import shutil
shutil.copy('/etc/hostname', '/var/tmp/testhostname')
maxschlepzig
источник
10
Просто любопытно, как вы создали эту таблицу?
Lightalchemist
16
@lightalchemist Я просто использовал vim в качестве блокнота, скопировал использованные символы юникода из таблицы википедии и скопировал результат в редактор стека переполнения для окончательной полировки.
maxschlepzig
3
Чем это отличается от другого ответа 2 года назад? stackoverflow.com/a/30359308/674039
Вим
1
@wim, вы должны сравнить мой ответ с версией ответа 2017 года, которую вы связали, которая была актуальна, когда я опубликовал свой ответ. Основные отличия: в моем ответе используются более качественные / более описательные заголовки столбцов, макет таблицы не отвлекает, он включает прямые ссылки в документацию, и я добавил столбец (т.е. «принимает файл obj»).
maxschlepzig
4
ХОРОШО. YMMV, но я думаю, что косметические изменения и подобные мелкие улучшения лучше вносить в виде правок существующих ответов, а не дублирования ответов.
Вим
104

В Python вы можете скопировать файлы, используя


import os
import shutil
import subprocess

1) Копирование файлов с использованием shutilмодуля

shutil.copyfile подпись

shutil.copyfile(src_file, dest_file, *, follow_symlinks=True)

# example    
shutil.copyfile('source.txt', 'destination.txt')

shutil.copy подпись

shutil.copy(src_file, dest_file, *, follow_symlinks=True)

# example
shutil.copy('source.txt', 'destination.txt')

shutil.copy2 подпись

shutil.copy2(src_file, dest_file, *, follow_symlinks=True)

# example
shutil.copy2('source.txt', 'destination.txt')  

shutil.copyfileobj подпись

shutil.copyfileobj(src_file_object, dest_file_object[, length])

# example
file_src = 'source.txt'  
f_src = open(file_src, 'rb')

file_dest = 'destination.txt'  
f_dest = open(file_dest, 'wb')

shutil.copyfileobj(f_src, f_dest)  

2) Копирование файлов с использованием osмодуля

os.popen подпись

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')

os.system подпись

os.system(command)


# In Linux/Unix
os.system('cp source.txt destination.txt')  

# In Windows
os.system('copy source.txt destination.txt')

3) Копирование файлов с использованием subprocessмодуля

subprocess.call подпись

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 подпись

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)

kmario23
источник
9
Использование однострочных команд - плохой стиль кодирования (гибкость, надежность и безопасность), вместо этого используйте ['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.
    """
    while True:
        copy_buffer = source.read(buffer_size)
        if not 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)
Пи.
источник
25
Некоторое время назад я заметил, что модуль называется 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')
user1016274
69

Используйте модуль shutil .

copyfile(src, dst)

Скопируйте содержимое файла с именем src в файл с именем dst. Место назначения должно быть доступно для записи; в противном случае возникнет исключение IOError. Если dst уже существует, он будет заменен. Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции. src и dst - это имена путей, заданные в виде строк.

Посмотрите на filesys все функции обработки файлов и каталогов, доступные в стандартных модулях Python.

Airsource Ltd
источник
Шутил на самом деле не копирует файлы. Есть большое толстое предупреждение прямо наверху документов . «Это означает, что владелец файла и группа будут потеряны, а также ACL. В Mac OS не используются ветвь ресурса и другие метаданные. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки ACL и альтернативные потоки данных не копируются ».
Человек
47

Пример копирования каталога и файла - Из материала Питона Тима Голдена:

http://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html

import os
import shutil
import tempfile

filename1 = tempfile.mktemp (".txt")
open (filename1, "w").close ()
filename2 = filename1 + ".copy"
print filename1, "=>", filename2

shutil.copy (filename1, filename2)

if os.path.isfile (filename2): print "Success"

dirname1 = tempfile.mktemp (".dir")
os.mkdir (dirname1)
dirname2 = dirname1 + ".copy"
print dirname1, "=>", dirname2

shutil.copytree (dirname1, dirname2)

if os.path.isdir (dirname2): print "Success"
Ноам Манос
источник
24

Во-первых, я сделал исчерпывающую таблицу методов шутиля для вашей справки.

shutil_methods =
{'copy':['shutil.copyfileobj',
          'shutil.copyfile',
          'shutil.copymode',
          'shutil.copystat',
          'shutil.copy',
          'shutil.copy2',
          'shutil.copytree',],
 'move':['shutil.rmtree',
         'shutil.move',],
 'exception': ['exception shutil.SameFileError',
                 'exception shutil.Error'],
 'others':['shutil.disk_usage',
             'shutil.chown',
             'shutil.which',
             'shutil.ignore_patterns',]
}

Во-вторых, объясните методы копирования в exmaples:

  1. shutil.copyfileobj(fsrc, fdst[, length]) манипулировать открытыми объектами
In [3]: src = '~/Documents/Head+First+SQL.pdf'
In [4]: dst = '~/desktop'
In [5]: shutil.copyfileobj(src, dst)
AttributeError: 'str' object has no attribute 'read'
#copy the file object
In [7]: with open(src, 'rb') as f1,open(os.path.join(dst,'test.pdf'), 'wb') as f2:
    ...:      shutil.copyfileobj(f1, f2)
In [8]: os.stat(os.path.join(dst,'test.pdf'))
Out[8]: os.stat_result(st_mode=33188, st_ino=8598319475, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067347, st_mtime=1516067335, st_ctime=1516067345)
  1. shutil.copyfile(src, dst, *, follow_symlinks=True) Скопируйте и переименуйте
In [9]: shutil.copyfile(src, dst)
IsADirectoryError: [Errno 21] Is a directory: ~/desktop'
#so dst should be a filename instead of a directory name
  1. shutil.copy() Копировать без сохранения метаданных
In [10]: shutil.copy(src, dst)
Out[10]: ~/desktop/Head+First+SQL.pdf'
#check their metadata
In [25]: os.stat(src)
Out[25]: os.stat_result(st_mode=33188, st_ino=597749, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516066425, st_mtime=1493698739, st_ctime=1514871215)
In [26]: os.stat(os.path.join(dst, 'Head+First+SQL.pdf'))
Out[26]: os.stat_result(st_mode=33188, st_ino=8598313736, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516066427, st_mtime=1516066425, st_ctime=1516066425)
# st_atime,st_mtime,st_ctime changed
  1. shutil.copy2() Копировать с сохранением метаданных
In [30]: shutil.copy2(src, dst)
Out[30]: ~/desktop/Head+First+SQL.pdf'
In [31]: os.stat(src)
Out[31]: os.stat_result(st_mode=33188, st_ino=597749, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067055, st_mtime=1493698739, st_ctime=1514871215)
In [32]: os.stat(os.path.join(dst, 'Head+First+SQL.pdf'))
Out[32]: os.stat_result(st_mode=33188, st_ino=8598313736, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067063, st_mtime=1493698739, st_ctime=1516067055)
# Preseved st_mtime
  1. shutil.copytree()

Рекурсивно скопировать все дерево каталогов с корнем в src, возвращая каталог назначения

Исчисление
источник
1
Шутил на самом деле не копирует файлы. Есть большое толстое предупреждение прямо наверху документов . «Это означает, что владелец файла и группа будут потеряны, а также ACL. В Mac OS не используются ветвь ресурса и другие метаданные. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки ACL и альтернативные потоки данных не копируются ».
Человек
19

Для небольших файлов и использования только встроенных Python, вы можете использовать следующую однострочную:

with open(source, 'rb') as src, open(dest, 'wb') as dst: dst.write(src.read())

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

yellow01
источник
3
Это читает весь исходный файл в память, прежде чем записать его обратно. Таким образом, это излишне тратит впустую память для всех, кроме самых маленьких операций копирования файла.
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это имя, которое я сгенерировал внутри программы.

Это решение только для Linux

отметка
источник
10
это не переносимо и не нужно, так как вы можете просто использовать 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[:]
ytpillai
источник
2
это кажется немного излишним, так как писатель должен обрабатывать буферизацию. for l in open('file.txt','r'): output.write(l)должен работать найти; просто настройте буфер потока вывода в соответствии с вашими потребностями. или вы можете переходить по байтам, повторяя попытку, output.write(read(n)); output.flush()где nуказано количество байтов, которое вы хотите записать за раз. оба из них также не имеют условия, чтобы проверить, что является бонусом.
владеет
1
Да, но я подумал, что, возможно, это будет легче понять, потому что он копирует целые строки, а не их части (в случае, если мы не знаем, сколько байтов каждая строка).
ytpillai
Очень верно. Кодирование для обучения и кодирование для эффективности очень разные.
владеет
1
глядя на источник - writelines вызывает write, hg.python.org/cpython/file/c6880edaf6f3/Modules/_io/bytesio.c . Кроме того, поток файлов уже открыт, поэтому для записи не нужно будет снова открывать его каждый раз.
владеет
2
Это ужасно Это делает ненужную работу без уважительной причины. Это не работает для произвольных файлов. Копия не идентична байту, если ввод имеет необычные окончания строк в таких системах, как Windows. Почему вы думаете, что это может быть легче понять, чем вызов функции копирования в shutil? Даже при игнорировании shutilпростой цикл чтения / записи блока (с использованием небуферизованного ввода-вывода) является простым, эффективным и имеет гораздо больший смысл, чем этот, и, следовательно, его легче учить и понимать.
maxschlepzig
11
from subprocess import call
call("cp -p <file> <file>", shell=True)
глубокое погружение
источник
10
Это зависит от платформы, поэтому я бы не стал использовать.
Кевин Мейер
5
Такое callнебезопасно. Пожалуйста, обратитесь к документу subproces об этом.
Buhtz
2
это не переносимо и не нужно, так как вы можете просто использовать shutil.
Кори Голдберг
2
Хм, почему Python, тогда?
Барис Демирай
Возможно, определите операционную систему перед запуском (будь то DOS или Unix, потому что они наиболее часто используются)
MilkyWay90
8

Начиная с Python 3.5 вы можете делать следующее для небольших файлов (например: текстовые файлы, маленькие JPEG):

from pathlib import Path

source = Path('../path/to/my/file.txt')
destination = Path('../path/where/i/want/to/store/it.txt')
destination.write_bytes(source.read_bytes())

write_bytes перезапишет все, что было в месте назначения

Марк
источник
2
И затем кто-то использует код (случайно или целенаправленно) для большого файла ... Использование функций из них shutilобрабатывает все особые случаи для вас и дает вам душевное спокойствие.
Марсель Вальдвогель,
4
по крайней мере, это не повторяет одни и те же решения снова и снова.
Жан-Франсуа Фабр
6
open(destination, 'wb').write(open(source, 'rb').read())

Откройте исходный файл в режиме чтения и запишите в целевой файл в режиме записи.

S471
источник
1
Идея хороша, а код красив, но правильная функция copy () может делать больше вещей, таких как копирование атрибутов (+ x бит) или, например, удаление уже скопированных байтов в случае, если найдено условие переполнения диска ,
Рауль Салинас-Монтеагудо
1
Все ответы требуют объяснения, даже если это одно предложение. Никакие объяснения не создают плохой прецедент и не помогают понять программу. Что если полный нуб Python придет и увидит это, захочет его использовать, но не сможет, потому что они этого не понимают? Вы хотите быть полезными для всех в своих ответах.
connectyourcharger
1
Разве это не скучает .close()по всем этим open(...)с?
luckydonald
Нет необходимости в .close (), поскольку мы нигде не храним объект указателя файла (ни для файла src, ни для файла назначения).
S471
1
Тот же самый неоптимальный подход, тратящий память, как ответ yellow01 .
maxschlepzig
-3

Python предоставляет встроенные функции для простого копирования файлов с помощью утилит операционной системы.

Следующая команда используется для копирования файла

shutil.copy(src,dst)

Следующая команда используется для копирования файла с информацией метаданных

shutil.copystat(src,dst)
Савай Махешвари
источник
copyЗатем вы должны запустить, copystatчтобы сохранить метаданные файла. В Python 3.3+ copystatтакже копируются расширенные атрибуты.
ingyhere