shutil - Operazioni di alto livello su file.

Scopo Operazioni di alto livello su file.
Versione Python 1.4 e successive

Il modulo shutil include operazioni di alto livello su file tipo la copiatura o l'impostazione dei permessi, ecc.

Copiare i file

copyfile() copia il contenuto della sorgente nella destinazione. Solleva IOError se non si possiedono i permessi per scrivere nel file di destinazione. Visto che la funzione apre il file di input per leggerlo, a prescindere dal tipo, i file speciali non possono essere copiati come nuovi file speciali con copyfile().

from shutil import *
from glob import glob

print 'PRIMA:', glob('shutil_copyfile.*')
copyfile('shutil_copyfile.py', 'shutil_copyfile.py.copy')
print 'DOPO :', glob('shutil_copyfile.*')
$ python shutil_copyfile.py
PRIMA: ['shutil_copyfile.py']
DOPO : ['shutil_copyfile.py', 'shutil_copyfile.py.copy' ]

copyfile() è scritta usando la funzione a basso livello copyfileobj() . Mentre i parametri per copyfile() sono nomi di file, quelli per copyfileobj() sono handle dei file aperti. Il terzo parametro (opzionale) è la lunghezza del buffer da usare per leggere porzioni di file (nel modo predefinito l'intero file viene letto tutto in una volta).

from shutil import *
import os
from StringIO import StringIO
import sys

class VerboseStringIO(StringIO):
    def read(self, n=-1):
        next = StringIO.read(self, n)
        print 'read(%d) =>' % n, next
        return next

lorem_ipsum = '''Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vestibulum aliquam mollis dolor. Donec vulputate nunc ut diam.
Ut rutrum mi vel sem. Vestibulum ante ipsum.'''

print 'Predefinito:'
input = VerboseStringIO(lorem_ipsum)
output = StringIO()
copyfileobj(input, output)

print

print 'Tutto in una volta:'
input = VerboseStringIO(lorem_ipsum)
output = StringIO()
copyfileobj(input, output, -1)

print

print 'Blocchi di 20:'
input = VerboseStringIO(lorem_ipsum)
output = StringIO()
copyfileobj(input, output, 20)

Il comportamento predefinito è quello di leggere usando grandi blocchi. Si usa -1 per leggere tutto l'input in una volta oppure un numero positivo per impostare la dimensione del blocco desiderata.

$ python shutil_copyfileobj.py
Predefinito:
read(16384) => Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vestibulum aliquam mollis dolor. Donec vulputate nunc ut diam.
Ut rutrum mi vel sem. Vestibulum ante ipsum.
read(16384) =>

Tutto in una volta:
read(-1) => Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vestibulum aliquam mollis dolor. Donec vulputate nunc ut diam.
Ut rutrum mi vel sem. Vestibulum ante ipsum.
read(-1) =>

Blocchi di 20:
read(20) => Lorem ipsum dolor si
read(20) => t amet, consectetuer
read(20) =>  adipiscing elit.
V
read(20) => estibulum aliquam mo
read(20) => llis dolor. Donec vu
read(20) => lputate nunc ut diam
read(20) => .
Ut rutrum mi vel
read(20) => sem. Vestibulum ante
read(20) =>  ipsum.
read(20) =>

La funzione copy() funziona come lo strumento da riga comandi di Unix cp . Se la destinazione designata corrisponde ad una directory invece che ad un file, viene creato un nuovo file nella directory usando il nome base della sorgente. I permessi per il file sono copiati assieme al contenuto.

from shutil import *
import os

os.mkdir('esempio')
print 'PRIMA:', os.listdir('esempio')
copy('shutil_copy.py', 'esempio')
print 'DOPO :', os.listdir('esempio')
$ python shutil_copy.py
PRIMA: []
DOPO : ['shutil_copy.py']

copy2() funziona come copy() , ma include data/ora di accesso e modifica nei meta-dati copiati nel nuovo file.

from shutil import *
import os
import time

def show_file_info(filename):
    stat_info = os.stat(filename)
    print '\tModo      :', stat_info.st_mode
    print '\tCreato    :', time.ctime(stat_info.st_ctime)
    print '\tAccesso   :', time.ctime(stat_info.st_atime)
    print '\tModificato:', time.ctime(stat_info.st_mtime)

os.mkdir('esempio')
print 'SORGENTE:'
show_file_info('shutil_copy2.py')
copy2('shutil_copy2.py', 'esempio')
print 'DESTIN:'
show_file_info('esempio/shutil_copy2.py')
$ python shutil_copy2.py
SORGENTE:
	Modo      : 33188
	Creato    : Sat Feb 27 12:16:29 2010
	Accesso   : Sat Feb 27 12:16:36 2010
	Modificato: Sat Feb 27 12:16:29 2010
DESTIN:
	Modo      : 33188
	Creato    : Sat Feb 27 12:16:36 2010
	Accesso   : Sat Feb 27 12:16:36 2010
	Modificato: Sat Feb 27 12:16:29 2010

Copiare i Meta-dati del file

In modalità predefinita in Unix, quando viene creato un nuovo file riceve i parmessi in base alla umask dell'utente corrente. Per copiare i permessi da un file ad un altro si usa copymode()

from shutil import *
from commands import *
import os

f = open('file_da_cambiare.txt', 'wt')
f.write('contenuto')
f.close()
os.chmod('file_da_cambiare.txt', 0444)

print 'PRIMA:', getstatus('file_da_cambiare.txt')
copymode('shutil_copymode.py', 'file_da_cambiare.txt')
print 'DOPO :', getstatus('file_da_cambiare.txt')

Prima occore creare un file da modificare

#!/bin/sh
# Crea un file che serve a shutil_copymode.py
touch file_da_cambiare.txt
chmod ugo+w file_da_cambiare.txt

L'esecuzione dello script modificherà i permessi.

$ python shutil_copymode.py
PRIMA: -r--r--r-- 1 robby robby 9 2010-02-27 12:22 file_da_cambiare.txt
DOPO : -rw-r--r-- 1 robby robby 9 2010-02-27 12:22 file_da_cambiare.txt

Per copiare altri meta-dati per un file (permessi, data/ora ultimo accesso, data/ora ultima modifica), si usa copystat() .

from shutil import *
import os
import time

def show_file_info(filename):
    stat_info = os.stat(filename)
    print '\tModo      :', stat_info.st_mode
    print '\tCreato    :', time.ctime(stat_info.st_ctime)
    print '\tAccesso   :', time.ctime(stat_info.st_atime)
    print '\tModificato:', time.ctime(stat_info.st_mtime)

f = open('file_da_cambiare.txt', 'wt')
f.write('contenuto')
f.close()
os.chmod('file_da_cambiare.txt', 0444)

print 'PRIMA:'
show_file_info('file_da_cambiare.txt')
copystat('shutil_copystat.py', 'file_da_cambiare.txt')
print 'DOPO :'
show_file_info('file_da_cambiare.txt')
python shutil_copystat.py
PRIMA:
	Modo      : 33060
	Creato    : Sat Feb 27 13:14:26 2010
	Accesso   : Sat Feb 27 13:14:26 2010
	Modificato: Sat Feb 27 13:14:26 2010
DOPO :
	Modo      : 33188
	Creato    : Sat Feb 27 13:14:26 2010
	Accesso   : Sat Feb 27 13:14:26 2010
	Modificato: Sat Feb 27 14:21:15 2010

Lavorare con Alberi di Directory

Il modulo shutil comprende 3 funzioni per lavorare con alberi di directory. Per copiare una directory da un posto ad un altro si usa copytree() . Attraversa ricorsivamente l'alberto di directory sorgente, copiandone i file nella destinazione. La directory destinazione non deve essere già esistente. Con il parametro symlinks si controlla se i collegamenti simbolici devono essere copiati come collegamenti o come file. Il modo predefinito è copiare il contenuto nei nuovi file. Se l'opione è True , vengono creati nuovi collegamenti simbolici nella destinazione.

Nota: La documentazione per copytree() dice che dovrebbe essere considerata una semplice implementazione piuttosto che uno strumento. Si potrebbe volere copiare l'implementazione e renderla più robusta, oppure aggiungere altre caratteristiche tipo un indicatore di progresso.

from shutil import *
from commands import *

print 'PRIMA:'
print getoutput('ls -rlast /tmp/esempio')
copytree('esempio', '/tmp/esempio')
print 'DOPO :'
print getoutput('ls -rlast /tmp/esempio')
$ python shutil_copytree.py
PRIMA:
ls: impossibile accedere a /tmp/esempio: Nessun file o directory
DOPO :
totale 12
4 -rw-r--r--  1 robby robby  494 2010-02-27 12:16 shutil_copy2.py
4 drwxr-xr-x  2 robby robby 4096 2010-02-27 12:16 .
4 drwxrwxrwt 15 root  root  4096 2010-02-27 13:24 ..

Per eliminare una directory ed il suo contenuto, si usa rmtree() . Gli errori sono sollevati come eccezioni in modalità predefinita. Gli errori possono essere ignorati se il secondo parametro è True , ed una funzione speciale per la gestione dell'errore può essere fornita come terzo parametro.

from shutil import *
from commands import *

print 'PRIMA:'
print getoutput('ls -rlast /tmp/esempio')
rmtree('/tmp/esempio')
print 'DOPO :'
print getoutput('ls -rlast /tmp/esempio')
$ python shutil_rmtree.py
PRIMA:
totale 12
4 -rw-r--r--  1 robby robby  494 2010-02-27 12:16 shutil_copy2.py
4 drwxr-xr-x  2 robby robby 4096 2010-02-27 12:16 .
4 drwxrwxrwt 15 root  root  4096 2010-02-27 13:24 ..
DOPO :
ls: impossibile accedere a /tmp/esempio: Nessun file o directory

Per spostare un file od una directory da un posto all'altro si usa move() . La semantica è simile a quella del comando Unix mv . Se la sorgente e la destinazione sono all'interno dello stesso filesystem, la sorgente viene semplicemente rinominata. Altrimenti la sorgente viene copiata nella destinazione, quindi la sorgente viene rimossa.

from shutil import *
from glob import glob

f = open('esempio.txt', 'wt')
f.write('contenuto')
f.close()

print 'PRIMA: ', glob('esempio*')
move('esempio.txt', 'esempio.out')
print 'DOPO : ', glob('esempio*')
$ python shutil_move.py
PRIMA:  ['esempio.txt']
DOPO :  ['esempio.out']

Vedere anche:

shutil
La documentazione della libreria standard per questo modulo.