Як скопіювати файл у Python?


2475

Як скопіювати файл у Python?

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


117
Здається, що cp не є системним викликом і тому не належить до модуля os. Це команда оболонки, тому вона вводиться в модуль shutil.
waldol1

Відповіді:


3006

shutilє багато методів, якими ви можете скористатися. Один з яких:

from shutil import copyfile
copyfile(src, dst)
  • Скопіюйте вміст файла з ім'ям src у файл з назвою dst .
  • Місце призначення повинно бути записаним; інакше буде піднято виняток IOError .
  • Якщо dst вже існує, його буде замінено.
  • Спеціальні файли, такі як символьні або блокові пристрої та труби, не можна скопіювати за допомогою цієї функції.
  • З копією , src та dst - назви шляхів, задані у вигляді рядків .

Якщо ви використовуєте os.pathоперації, copyскоріше використовуйте copyfile. copyfileбуде приймати тільки рядок .


147
Чим відрізняється копія від копіювального файлу?
Метт

385
в копії (src, dst) dst може бути каталогом.
Оуен

41
Зауважте, що не всі метадані будуть скопійовані, залежно від вашої платформи.
Кевін Хорн

12
Зауважте, що це не атомна операція. Будьте обережні, використовуючи його в потоковому додатку.
водний байт

4
Зауважте, що він не може обробляти скорочення, як ~, але він може мати відносні шляхи
zwep

1252
┌──────────────────┬────────┬───────────┬───────┬────────────────┐
│     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       │
└──────────────────┴────────┴───────────┴───────┴────────────────┘

732

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
@Vijay Я вважаю, що ця накладні витрати пояснюються копією метаданих.
Джонатан Н

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

10
Просто цікаво, як ви створили цю таблицю?
лігтальхімік

16
@lightalchemist Я щойно використав vim як скретчпад, скопіював використані символи unicode з таблиці wikipedia та скопіював результат у редактор stackoverflow для остаточного полірування.
maxschlepzig

3
Чим це відрізняється від інших відповідей на 2 роки раніше? stackoverflow.com/a/30359308/674039
wim

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)


9
Використовувати однорядкові команди - це поганий стиль кодування (гнучкість, надійність та безпека), натомість використовуйте ['copy', sourcefile, destfile]синтаксис, де це можливо, особливо якщо параметри надходять з користувальницьких даних.
Марсель Вальдвогель

8
Чому ви перераховуєте так багато поганих альтернатив функції shutil copy?
maxschlepzig

6
shutil вбудований, не потрібно надавати не портативні альтернативи. Відповідь можна фактично покращити, видаливши системні рішення, і після цього видалення ця відповідь є лише копією існуючих відповідей / копією документації.
Жан-Франсуа Фабре

3
os.popenна деякий час застаріла. і check_outputне повертає статус, але вихід (який у випадку порожній copy/cp)
Жан-Франсуа Фабре

2
shutil насправді не копіює файли. У верхній частині документу є велике попередження про жир . "це означає, що власник файлів і група втрачаються, а також ACL. На Mac OS не використовуються вилки ресурсів та інші метадані. Це означає, що ресурси будуть втрачені, а тип файлу та коди творців не будуть правильними. У Windows, власники файлів, ACL та альтернативні потоки даних не копіюються. "
gman

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

Використовуйте шутильний модуль .

copyfile(src, dst)

Скопіюйте вміст файла з ім'ям src у файл з назвою dst. Місце призначення повинно бути записаним; інакше буде піднято виняток IOError. Якщо dst вже існує, його буде замінено. Спеціальні файли, такі як символьні або блокові пристрої та труби, не можна скопіювати за допомогою цієї функції. src і dst - це назви шляхів, задані у вигляді рядків.

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


shutil насправді не копіює файли. У верхній частині документу є велике попередження про жир . "це означає, що власник файлів і група втрачаються, а також ACL. На Mac OS не використовуються вилки ресурсів та інші метадані. Це означає, що ресурси будуть втрачені, а тип файлу та коди творців не будуть правильними. У Windows, власники файлів, ACL та альтернативні потоки даних не копіюються. "
gman

47

Приклад копіювання каталогів та файлів - із матеріалу Python Tim Tim Golden:

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',]
}

По-друге, поясніть методи копіювання у прикладах:

  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
shutil насправді не копіює файли. У верхній частині документу є велике попередження про жир . "це означає, що власник файлів і група втрачаються, а також ACL. На Mac OS не використовуються вилки ресурсів та інші метадані. Це означає, що ресурси будуть втрачені, а тип файлу та коди творців не будуть правильними. У Windows, власники файлів, ACL та альтернативні потоки даних не копіюються. "
gman

19

Для невеликих файлів та використання лише вбудованих файлів python ви можете використовувати наступний однокласник:

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

Як @maxschlepzig згадується в коментарях нижче, це не оптимальний спосіб для додатків, де файл занадто великий або коли пам'ять критична, тому відповіді Сваті слід віддавати перевагу.


3
Це зчитує повний вихідний файл у пам'ять перед тим, як записати його назад. Таким чином, це зайво витрачає пам'ять на всі операції з копіювання файлів, крім найменших.
maxschlepzig

1
Це правда? Я думаю, .read()і .write()вони буферизовані за замовчуванням (принаймні для CPython).
саундстріп

@soundstripe, Звичайно, це правда. Той факт, що об’єкт файлу, повернутий open()буферизованим IO, за замовчуванням не допомагає вам тут, тому що read()вказано як: "Якщо n від'ємне чи пропущене, читайте до EOF." Це означає, що read()повертає весь вміст файлу у вигляді рядка.
maxschlepzig

@maxschlepzig Я розумію, що я цього не знав. Я дав цю відповідь, якщо хтось захотів зробити просту копію файлу, використовуючи лише вбудовані модулі, не потребуючи імпорту модуля. Звичайно, оптимізація пам’яті не повинна турбувати, якщо ви хочете цю опцію. Все одно дякую, що очистили це. Відповідно я оновив відповідь.
жовтий01

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
shutil є більш портативним
Іадор

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[:]

2
це здається трохи зайвим, оскільки письменник повинен працювати з буферизацією. for l in open('file.txt','r'): output.write(l)слід працювати знайти; просто налаштуйте буфер вихідного потоку під свої потреби. або ви можете перейти за байтами, переглянувши спробу, output.write(read(n)); output.flush()де nкількість байтів, які ви хотіли б написати за один раз. вони також не мають умови перевірити, що є бонусом.
володіє

1
Так, але я подумав, що, можливо, це може бути простіше зрозуміти, оскільки він копіює цілі рядки, а не їх частини (якщо ми не знаємо, скільки байтів у кожному рядку).
ytpillai

Дуже правильно. Кодування для навчання та кодування для ефективності дуже різні.
володіє

1
дивлячись на джерело - посилань на виклики write, hg.python.org/cpython/file/c6880edaf6f3/Modules/_io/bytesio.c . Крім того, потік файлів уже відкритий, тому запис не потрібно буде його знову відкривати кожен раз.
належить

2
Це жахливо. Вона робить непотрібну роботу без поважних причин. Він не працює для довільних файлів. Копія не є байт-ідентичною, якщо вхід має незвичні закінчення рядків у таких системах, як Windows. Чому ви вважаєте, що це може бути легше зрозуміти, ніж заклик до функції копіювання shutil? Навіть при ігноруванні shutilпростий блок циклу читання / запису (використовуючи нерозподілений IO) прямо вперед, був би ефективним і мав би набагато більше сенсу, ніж це, і, таким чином, напевно легше навчати та розуміти.
maxschlepzig

11
from subprocess import call
call("cp -p <file> <file>", shell=True)

10
Це залежить від платформи, тому я б не використовував це.
Кевін Мейєр

5
Таке callє незахищеним. Будь ласка, ознайомтесь із документацією щодо цього підпроцесу.
buhtz

2
це не портативно, а непотрібно, оскільки ви можете просто використовувати shutil.
Корі Голдберг

2
Хм, чому тоді Python?
Baris Demiray

Можливо, виявіть операційну систему перед запуском (будь то DOS чи Unix, тому що це два найбільш вживаних)
MilkyWay90

8

З Python 3.5 ви можете зробити наступне для невеликих файлів (тобто: текстові файли, невеликі jpegs):

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

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


1
Ідея приємна, і код прекрасний, але належна функція copy () може робити більше речей, таких як копіювання атрибутів (+ x біт) або, наприклад, видалення вже скопійованих байтів у випадку, якщо буде знайдено умова, наповнене диском .
Рауль Салінас-Монтеагудо

1
Усі відповіді потребують пояснення, навіть якщо це одне речення. Жодне пояснення не призводить до поганого прецеденту і не допомагає зрозуміти програму. Що робити, якщо повний нобіт Python прийшов і побачив це, хотів ним скористатися, але не міг, тому що вони цього не розуміють? Ви хочете бути корисними для всіх у своїх відповідях.
Підключіть свій зарядний пристрій

1
Хіба цього не вистачає .close()на всіх цих open(...)s?
luckydonald

Не потрібно .close (), оскільки ми НЕ Зберігаємо об’єкт вказівника файлу нікуди (ні для src-файлу, ні для файла призначення).
S471

1
Той самий неоптимальний підхід до втрати пам'яті, як і відповідь yellow01 .
maxschlepzig

-3

Python пропонує вбудовані функції для легкого копіювання файлів за допомогою утилітів оболонки операційної системи.

Наступна команда використовується для копіювання файлу

shutil.copy(src,dst)

Наступна команда використовується для копіювання файлу з інформацією про метадані

shutil.copystat(src,dst)

copyПотім слід запустити, copystatщоб зберегти метадані файлів. У Python 3.3+ copystatтакож копіюються розширені атрибути.
ingyhere
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.