1. 程式人生 > 其它 >Python複製拷貝檔案的9個方法

Python複製拷貝檔案的9個方法

轉自:https://zhuanlan.zhihu.com/p/35725217

用Python複製檔案的9個方法

Python 中有許多“開蓋即食”的模組(比如 os,subprocess 和 shutil)以支援檔案 I/O 操作。在這篇文章中,你將會看到一些用 Python 實現檔案複製的特殊方法。下面我們開始學習這九種不同的方法來實現 Python 複製檔案操作。

在開始之前,你必須明白為什麼瞭解最適合你的 Python 複製檔案方法是如此重要。這是因為檔案 I/O 操作屬於效能密集型而且經常會達到瓶頸。這就是為什麼你應該根據你的應用程式的設計選擇最好的方法。

一些共享資源的程式會傾向於以阻塞模式來複制檔案,而有些則可能希望以非同步方式執行。比如 — 使用執行緒來複制檔案或者啟動單獨的程序來實現它。還有一點需要考慮的是平臺的可移植性。這意味著你應該知道你要執行的程式所在的目標作業系統(Windows/Linux/Mac OS X 等)。

用 Python 複製檔案的 9 種方法具體是:

  • shutil copyfile() 方法
  • shutil copy() 方法
  • shutil copyfileobj() 方法
  • shutil copy2() 方法
  • os popen 方法
  • os system() 方法
  • threading Thread() 方法
  • subprocess call() 方法
  • subprocess check_output() 方法

Shutil Copyfile()方法

只有當目標是可寫的,這個方法才會將源內容複製到目標位置。如果你沒有寫入許可權,則會導致 IOError 異常。

它會開啟輸入檔案進行讀取並忽略其檔案型別。接下來,它不會以任何不同的方式處理特殊檔案,也不會將它們複製為新的特殊檔案。

Copyfile() 方法使用下面的低階函式 copyfileobj()。它將檔名作為引數,開啟它們並將檔案控制代碼傳遞給 copyfileobj()。這個方法中有一個可選的第三個引數,你可用它來指定緩衝區長度。然後它會開啟檔案並讀取指定緩衝區大小的塊。但是,預設是一次讀取整個檔案。

copyfile(source_file, destination_file)

以下是關於 copyfile() 方法的要點。

它將源內容複製到目標檔案中。

如果目標檔案不可寫入,那麼複製操作將導致 IOError 異常。

如果原始檔和目標檔案都相同,它將會返回 SameFileError。

但是,如果目標檔案之前有不同的名稱,那麼該副本將會覆蓋其內容。

如果目標是一個目錄,這意味著此方法不會複製到目錄,那麼會發生 Error 13。

它不支援複製諸如字元或塊驅動以及管道等檔案。

# Python Copy File - Sample Code

from shutil import copyfile
from sys import exit

source = input("Enter source file with full path: ")
target = input("Enter target file with full path: ")

# adding exception handling
try:
   copyfile(source, target)
except IOError as e:
   print("Unable to copy file. %s" % e)
   exit(1)
except:
   print("Unexpected error:", sys.exc_info())
   exit(1)

print("\nFile copy done!\n")

while True:
   print("Do you like to print the file ? (y/n): ")
   check = input()
   if check == 'n':
       break
   elif check == 'y':
       file = open(target, "r")
       print("\nHere follows the file content:\n")
       print(file.read())
       file.close()
       print()
       break
   else:
       Continue

Shutil Copy()方法

copyfile(source_file, [destination_file or dest_dir])
copy() 方法的功能類似於 Unix 中的“cp”命令。這意味著如果目標是一個資料夾,那麼它將在其中建立一個與原始檔具有相同名稱(基本名稱)的新檔案。此外,該方法會在複製原始檔的內容後同步目標檔案許可權到原始檔。
import os
import shutil

source = 'current/test/test.py'
target = '/prod/new'

assert not os.path.isabs(source)
target = os.path.join(target, os.path.dirname(source))

# create the folders if not already exists
os.makedirs(target)

# adding exception handling
try:
   shutil.copy(source, target)
except IOError as e:
   print("Unable to copy file. %s" % e)
except:
   print("Unexpected error:", sys.exc_info())

copy() vs copyfile() :

copy() 還可以在複製內容時設定許可權位,而 copyfile() 只複製資料。

如果目標是目錄,則 copy() 將複製檔案,而 copyfile() 會失敗,出現 Error 13。

有趣的是,copyfile() 方法在實現過程中使用 copyfileobj() 方法,而 copy() 方法則是依次使用 copyfile() 和 copymode() 函式。

在 Potion-3 可以很明顯看出 copyfile() 會比 copy() 快一點,因為後者會有一個附加任務(保留許可權)。

Shutil Copyfileobj()方法

該方法將檔案複製到目標路徑或者檔案物件。如果目標是檔案物件,那麼你需要在呼叫 copyfileobj() 之後關閉它。它還假定了一個可選引數(緩衝區大小),你可以用來設定緩衝區長度。這是複製過程中儲存在記憶體中的位元組數。系統使用的預設大小是 16KB。

from shutil import copyfileobj
status = False
if isinstance(target, string_types):
   target = open(target, 'wb')
   status = True
try:
   copyfileobj(self.stream, target, buffer_size)
finally:
   if status:
       target.close()

Shutil Copy2()方法

雖然 copy2() 方法的功能類似於 copy()。但是它可以在複製資料時獲取元資料中新增的訪問和修改時間。複製相同的檔案會導致 SameFileError 異常。

copy() vs copy2() :

copy() 只能設定許可權位,而 copy2() 還可以使用時間戳來更新檔案元資料。

copy() 在函式內部呼叫 copyfile() 和 copymode(), 而 copy2() 是呼叫 copystat() 來替換copymode()。

Os Popen()方法

from shutil import *
import os 
import time
from os.path import basename

def displayFileStats(filename):
   file_stats = os.stat(basename(filename))
   print('\tMode    :', file_stats.st_mode)
   print('\tCreated :', time.ctime(file_stats.st_ctime))
   print('\tAccessed:', time.ctime(file_stats.st_atime))
   print('\tModified:', time.ctime(file_stats.st_mtime))

os.mkdir('test')

print('SOURCE:')
displayFileStats(__file__)

copy2(__file__, 'testfile')

print('TARGET:')
displayFileStats(os.path.realpath(os.getcwd() + '/test/testfile'))

該方法建立一個傳送或者接受命令的管道。它返回一個開啟的並且連線管道的檔案物件。你可以根據檔案開啟模式將其用於讀取或者寫入比如‘r’(預設)或者‘w’。

os.popen(command[, mode[, bufsize]])

mode – 它可以是‘r’(預設)或者‘w’

Bufsize – 如果它的值是0,那麼就不會出現緩衝。如果將它設定為1,那麼在訪問檔案時就會發生行緩衝。如果你提供一個大於1的值,那麼就會在指定緩衝區大小的情況下發生緩衝。但是,對於負值,系統將採用預設緩衝區大小。

對於Windows系統:

import os
os.popen('copy 1.txt.py 2.txt.py')

對於Liunx系統:

import os
os.popen('cp 1.txt.py 2.txt.py')

Os System()方法

這是執行任何系統命令的最常用方式。使用 system() 方法,你可以呼叫 subshell 中的任何命令。在內部,該方法將呼叫 C 語言的標準庫函式。

該方法返回該命令的退出狀態。

對於 Windows 系統:

import os
os.system('copy 1.txt.py 2.txt.py')

對於 Liunx 系統:

import os
os.system('cp 1.txt.py 2.txt.py')

使用非同步方式的執行緒庫複製檔案

如果你想以非同步方式複製檔案,那麼使用下面的方法。在這裡,我們使用 Python 的執行緒模組在後臺進行復制操作。

在使用這種方法時,請確保使用鎖定以避免鎖死。如果你的應用程式使用多個執行緒讀取/寫入檔案,就可能會遇到這種情況。

import shutil
from threading import Thread

src="1.txt.py"
dst="3.txt.py"

Thread(target=shutil.copy, args=[src, dst]).start()

使用Subprocess的Call()方法複製檔案

Subprocess 模組提供了一個簡單的介面來處理子程序。它讓我們能夠啟動子程序,連線到子程序的輸入/輸出/錯誤管道,並檢索返回值。

subprocess 模組旨在替換舊版模組和函式,比如 – os.system, os.spawn*, os.popen*, popen2.*

它使用 call() 方法呼叫系統命令來執行使用者任務。

import subprocess

src="1.txt.py"
dst="2.txt.py"
cmd='copy "%s" "%s"' % (src, dst)

status = subprocess.call(cmd, shell=True)

if status != 0:
    if status < 0:
        print("Killed by signal", status)
    else:
        print("Command failed with return code - ", status)
else:
    print('Execution of %s passed!\n' % cmd)

使用 subprocess 中的 Check_output() 方法複製檔案

使用 subprocess 中的 Check_output() 方法,你可以執行外部命令或程式並捕獲其輸出。它也支援管道。

import os, subprocess

src=os.path.realpath(os.getcwd() + "http://cdn.techbeamers.com/1.txt.py")
dst=os.path.realpath(os.getcwd() + "http://cdn.techbeamers.com/2.txt.py")
cmd='copy "%s" "%s"' % (src, dst)

status = subprocess.check_output(['copy', src, dst], shell=True)

print("status: ", status.decode('utf-8'))