Introduzione
Quando si tratta di usare Python per copiare i file, ci sono due modi principali: usare il modulo shutil
o il modulo os
. Tutti i metodios
che mostriamo qui sono metodi che ci permettono di eseguire comandi di shell dal nostro codice Python, che useremo per eseguire il comandocopy
(Windows) o il comandocp
(Unix).
Noterai che molti di questi metodi, sia nel moduloshutil
che nel moduloos
, hanno funzionalità molto simili (il che non dovrebbe essere sorprendente), ma ognuno varia in funzionalità l’uno dall’altro molto leggermente, che spiegherò anche.
Copiare i file con il modulo shutil
Il modulo shutil offre diversi metodi di alto livello per copiare i file. Di seguito sono riportati i principali:
copyfile
Questo metodo copia il contenuto di un file in un altro file. La destinazione fornita deve essere un file scrivibile e avere un nome diverso dal file di origine. Se i nomi sono gli stessi, genererà un errore. Se il file di destinazione esiste già, verrà sostituito con il file appena copiato.
La sintassi per questo metodo è:
shutil.copyfile(src_file, dest_file, *, follow_symlinks=True)
Ad esempio, il codice seguente copierà un file denominato “file1.txt “in un file denominato” file2.txt”:
import shutilshutil.copyfile('file1.txt', 'file2.txt')
Una caratteristica interessante e potenzialmente utile di shutil.copyfile
è l’argomento booleano follow_symlinks
. Se è impostato su False
e il file sorgente è un collegamento simbolico, invece di copiare il file, verrà creato un nuovo collegamento simbolico.
copia
Questo metodo è molto simile acopyfile
, con la differenza principale che oltre a copiare il contenuto del file sorgente, fa un ulteriore passo avanti e copia anche i permessi del file system del file. Copiare i permessi dei file non è un compito banale nella maggior parte dei linguaggi di programmazione, quindi questa è una bella caratteristica da avere.
La sintassi è la seguente:
shutil.copy(src_file, dest_file, *, follow_symlinks=True)
Ognuno di questi parametri è lo stesso del metodo copyfile
. Ad esempio, il seguente codice copierà “file1.txt “into” file3.txt”.
import shutilshutil.copy('file1.txt', 'file3.txt')
Nota: assicurati di non nominare il tuo script come uno dei moduli che stai importando (cosa che ho erroneamente fatto durante il test del codice per questo articolo). Se lo fai, riceverai un errore durante il tentativo di importare quel modulo a causa di un problema di importazione circolare.
copy2
Come con i metodi precedenti, il metodocopy2
è identico al metodocopy
, ma oltre a copiare il contenuto del file tenta anche di preservare tutti i metadati del file sorgente. Se la piattaforma non consente il salvataggio completo dei metadati, copy2
non restituisce l’errore e conserverà solo i metadati che può.
La sintassi è la seguente:
shutil.copy2(src_file, dest_file, *, follow_symlinks=True)
Ancora una volta, questi parametri sono gli stessi dei comandi precedenti che abbiamo menzionato finora.
Ad esempio, il seguente codice copierà “file1.txt “into” file4.txt”, così come preservare i metadati del file originale, ” file1.txt”.
import shutilshutil.copy2('file1.txt', 'file4.txt')
$ python copy-files.py $ ls -ltotal 32-rw-r--r-- 1 scott staff 91 Oct 27 11:26 copy-files.py-rw-r--r-- 1 scott staff 6 Oct 27 11:27 file1.txt-rw-r--r-- 1 scott staff 6 Oct 27 11:29 file3.txt-rw-r--r-- 1 scott staff 6 Oct 27 11:27 file4.txt
Come possiamo vedere eseguendo il nostro codice sopra, “file1.txt “è stato copiato in” file4.txt”. Tuttavia, potresti aver notato che la data di creazione è stata conservata nel nuovo file, a differenza di shutil.copy
, che ha copiato ” file1.txt ” a ” file3.txt ” e gli ha dato una nuova data di creazione.
copyfileobj
Questo metodo copia il contenuto di un file sorgente in un file di destinazione, dalla posizione corrente del file sorgente. Ciò significa che se leggi i dati dal tuo oggetto file sorgente, la posizione in cui interrompi la lettura è la posizione da cui inizia la copia copyfileobj
.
La sintassi è la seguente:
shutil.copyfileobj(src_file_object, dest_file_object)
I significati dei parametri del file di origine e di destinazione sono simili ai comandi precedenti, ma ora si riferiscono agli oggetti. Il parametro length è facoltativo e rappresenta la dimensione del buffer ovvero il numero di bit tenuti in memoria durante il processo di copia. Questa opzione può essere utile quando si copiano file di grandi dimensioni, in quanto può accelerare il processo di copia ed evitare l’utilizzo incontrollato della memoria.
Ad esempio il seguente codice copierà “file1.txt “into” file5.txt ”
import shutilfilename1 = 'file1.txt'fileA = open(filename1, 'rb')filename2 = 'file5.txt'fileB = open(filename2, 'wb')shutil.copyfileobj(fileA, fileB)
Come possiamo vedere, per usare copyfileobj
, dobbiamo aprire i file in modalità binaria (che è la parte “b” di “rb” e “wb”). Inoltre, il file di origine deve essere aperto come leggibile e il file di destinazione deve essere aperto come scrivibile (le parti” r “e” w”, rispettivamente).
Copia di file con il modulo os
Il modulo os fornisce un modo per utilizzare la funzionalità del sistema operativo per copiare i file. Nella maggior parte (se non tutti) degli esempi da qui in avanti forniamo esempi che funzionano sia per Windows che per Unix. Gli esempi sono diversi a causa dei comandi di shell utilizzati, quindi assicurati di prestare attenzione a come ogni chiamata di funzione è etichettata nei commenti Python.
popen
Questo metodo apre una pipe verso o dal comando. Tuttavia, si noti che questo metodo è stato deprecato in Python 2.6, quindi non è consigliabile utilizzarlo a meno che non sia necessario. In alternativa, la documentazione Python ci consiglia di utilizzare i metodi del modulo sottoprocesso.
La sintassi è la seguente:
os.popen(cmd])
Qui il valore restituito è un oggetto file collegato alla pipe. Questo oggetto può essere letto o scritto a seconda della modalità. La modalità predefinita è ‘r’, che consente la lettura del contenuto del file.
L’esempio seguente copierà ” file1.txt “into” file6.txt”:
import os# Windowsos.popen('copy file1.txt file6.txt')# Unixos.popen('cp file1.txt file6.txt')
Eseguire il comando in questo modo è esattamente come se lo si eseguisse direttamente dalla riga di comando del terminale.
system
Questo metodo esegue il comando specificato in una subshell. È disponibile sia per Unix che per Windows. La sintassi è la seguente:
os.system(command)
Qui command
è una stringa contenente il comando DOS o Unix shell. Nel nostro caso, questo è dove inseriremo il comandocopy
ocp
.
Ad esempio, il seguente codice copierà “file1.txt “into” file7.txt ”
import os# Windowsos.system('copy file1.txt file7.txt')# Unixos.system('cp file1.txt file7.txt')
Questo sembra identico al precedente comando os.popen
che abbiamo appena usato, ma il comando viene eseguito in una subshell, il che significa che viene eseguito in un thread separato in parallelo al codice in esecuzione. Per attendere il suo completamento, è necessario chiamare .wait()
sull’oggetto restituito da os.system
.
Copia di file con il modulo sottoprocesso
Il modulo sottoprocesso intende sostituire alcuni metodi nel moduloos
(in particolareos.system
eos.spawn*
), e presenta due metodi principali per accedere ai comandi del sistema operativo. Questi metodi sono call
echeck_output
. Ancora una volta, per i sistemi Unix, il comando “copia file1.file txt 2.txt “dovrebbe essere sostituito da” cp file1.file txt 2.txt”.
Metodo di chiamata
La documentazione Python ci consiglia di utilizzare il metodocall
per avviare un comando dal sistema operativo.
La sintassi è la seguente:
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
Il parametroargs
includerà il nostro comando shell. Tuttavia, una parola di cautela, poiché la documentazione di Python ci avverte che l’uso di shell=True
può essere un rischio per la sicurezza.
Usando questa chiamata di funzione, possiamo eseguire il nostro comando di copia come segue:
import subprocess# Windowsstatus = subprocess.call('copy file1.txt file8.txt', shell=True)# Unixstatus = subprocess.call('cp file1.txt file8.txt', shell=True)
Come mostra l’esempio sopra, abbiamo semplicemente bisogno di passare una stringa con il comando shell, come prima.
E come previsto, il sistema operativo copierà ” file1.txt “in un file denominato” file8.txt”.
Metodo check_output
Questo metodo ci permette anche di eseguire un comando all’interno di una shell. È molto simile al comandosubprocess.run
, tranne che per impostazione predefinita convoglia i dati da stdout come byte codificati. La sintassi è la seguente:
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
Qui il parametro args
include il comando della shell che vogliamo usare. Ancora una volta, la documentazione Python ci avverte di usare shell=True
, quindi usa questo metodo con cautela.
Nel seguente codice copieremo ” file1.txt ” a ” file9.txt ” usando il comandocheck_output
:
import subprocess# Windowsstatus = subprocess.check_output('copy file1.txt file9.txt', shell=True)# Unixstatus = subprocess.check_output('cp file1.txt file9.txt', shell=True)
E come con tutti i comandi che abbiamo mostrato in questo articolo, questo copierà il file ” file1.txt ” alla destinazione che abbiamo specificato, che è “file9.txt ” qui.
Wrapping Up
Python ci offre molti modi diversi per copiare i file, alcuni dei quali fanno parte del set di metodi Python. Altri usano alcuni dei potenti metodi di Python per eseguire comandi in una shell, che utilizzano comandi di shell comecopy
ocp
.
Non sei sicuro di quale sia giusto per te? Abbiamo presentato molti modi diversi per copiare i file qui, quindi è comprensibile. Il metodo utilizzato per copiare un file dipende completamente da te e dipenderà dalle tue esigenze specifiche. Sebbene nella maggior parte dei casi uno dei comandi shutil
funzionerà bene per te. Prova a iniziare con shutil.copy2
e vedi se fa ciò di cui hai bisogno.