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.