10.10. shutil — 高水準のファイル操作

ソースコード: Lib/shutil.py


shutil モジュールはファイルやファイルの集まりに対する高水準の操作方法を多数提供します。特にファイルのコピーや削除のための関数が用意されています。個別のファイルに対する操作については、 os モジュールも参照してください。

警告

高レベルなファイルコピー関数 (shutil.copy(), shutil.copy2()) でも、全てのファイルのメタデータをコピーできるわけではありません。

POSIXプラットフォームでは、これはACLやファイルのオーナー、グループが失われることを意味しています。 Mac OSでは、リソースフォーク(resource fork)やその他のメタデータが利用されません。これは、リソースが失われ、ファイルタイプや生成者コード(creator code)が正しくなくなることを意味しています。 Windowsでは、ファイルオーナー、ACL、代替データストリームがコピーされません。

10.10.1. ディレクトリとファイルの操作

shutil.copyfileobj(fsrc, fdst[, length])

ファイル形式のオブジェクト fsrc の内容を fdst へコピーします。整数値 length は与えられた場合バッファサイズを表します。特に length が負の場合、チャンク内のソースデータを繰り返し操作することなくデータをコピーします。デフォルトでは、制御不能なメモリ消費を避けるためにデータはチャンク内に読み込まれます。 fsrc オブジェクトの現在のファイル位置が0でない場合、現在の位置からファイル終端までの内容のみがコピーされることに注意してください。

shutil.copyfile(src, dst)

src で指定されたファイルの内容を dst で指定されたファイルへとコピーします。(メタデータはコピーされません) dst は完全なターゲットファイル名である必要があります。コピー先にディレクトリ名を使用したい場合は、 shutil.copy() を参照してください。もし、 srcdst が同じファイルであれば、 Error 例外が発生します。コピー先は書き込み可能である必要があります。そうでなければ IOError を発生します。もし dst が存在したら、置き換えられます。キャラクタやブロックデバイス、パイプ等の特別なファイルはこの関数ではコピーできません。 srcdst にはパス名を文字列で与えられます。

shutil.copymode(src, dst)

src から dst へパーミッションをコピーします。ファイル内容や所有者、グループは影響を受けません。 srcdst には文字列としてパス名を与えられます。

shutil.copystat(src, dst)

src から dst へ、パーミッション、最終アクセス時間、最終更新時間、フラグをコピーします。ファイル内容や所有者、グループは影響を受けません。 srcdst には文字列としてパス名を与えられます。

shutil.copy(src, dst)

ファイル src をファイルまたはディレクトリ dist へコピーします。もし、 dst がディレクトリであればファイル名は src と同じものが指定されたディレクトリ内に作成(または上書き)されます。パーミッションはコピーされます。 srcdst には文字列としてパス名を与えられます。

shutil.copy2(src, dst)

shutil.copy() と類似していますが、メタデータも同様にコピーされます。実際のところ、この関数は shutil.copy() の後に copystat() しています。 Unix コマンドの cp -p と同様の働きをします。

shutil.ignore_patterns(*patterns)

このファクトリ関数は、 copytree() 関数の ignore 引数に渡すための呼び出し可能オブジェクトを作成します。 glob形式の patterns にマッチするファイルやディレクトリが無視されます。下の例を参照してください。

バージョン 2.6 で追加.

shutil.copytree(src, dst, symlinks=False, ignore=None)

src を起点としたディレクトリツリーをコピーします。 dst で指定されたターゲットディレクトリは、既存のもので無い必要があります。存在しない親ディレクトリも含めて作成されます。パーミッションと時刻は copystat() 関数でコピーされます。個々のファイルは shutil.copy2() によってコピーされます。

symlinks が真であれば、元のディレクトリ内のシンボリックリンクはコピー先のディレクトリ内へシンボリックリンクとしてコピーされます。偽が与えられたり省略された場合は元のディレクトリ内のリンクの対象となっているファイルがコピー先のディレクトリ内へコピーされます。

ignorecopytree() が走査しているディレクトリと os.listdir() が返すその内容のリストを引数として受け取ることのできる呼び出し可能オブジェクトでなければなりません。 copytree() は再帰的に呼び出されるので、 ignore はコピーされる各ディレクトリ毎に呼び出されます。 ignore の戻り値はカレントディレクトリに相対的なディレクトリ名およびファイル名のシーケンス(すなわち第二引数の項目のサブセット)でなければなりません。それらの名前はコピー中に無視されます。 ignore_patterns() を用いて glob 形式のパターンによって無視する呼び出し可能オブジェクトを作成することが出来ます。

例外が発生した場合、理由のリストとともに Error を送出します。

この関数は、究極の道具としてではなく、ソースコードが利用例になっていると捉えるべきでしょう。

バージョン 2.3 で変更: コピー中にエラーが発生した場合、メッセージを出力するのではなく Error を起こす。

バージョン 2.5 で変更: dst を作成する際に中間のディレクトリ作成が必要な場合、エラーを起こすのではなく作成する。ディレクトリのパーミッションと時刻を copystat() を利用してコピーする。

バージョン 2.6 で変更: 何がコピーされるかを制御するための ignore 引数

shutil.rmtree(path[, ignore_errors[, onerror]])

ディレクトリツリー全体を削除します。 path はディレクトリを指しているなければなりません(ただしディレクトリに対するシンボリックリンクではいけません)。もし ignore_errors が真であれば削除に失敗したことによるエラーは無視されます。偽や省略された場合はこれらのエラーは onerror で与えられたハンドラを呼び出して処理され、 onerror が省略された場合は例外を送出します。

onerror が与えられた場合、それは3つのパラメータ function, path および excinfo を受け入れて呼び出し可能のものでなくてはなりません。最初のパラメータ function は例外を引き起こした関数で os.listdir(), os.remove(), os.rmdir() のいずれかでしょう。 2番目のパラメータ pathfunction へ渡されたパス名です。 3番目のパラメータ excinfosys.exc_info() で返されるような例外情報になるでしょう。 onerror が引き起こす例外はキャッチできません。

バージョン 2.6 で変更: path を明示的にチェックして、シンボリックリンクだった場合は OSError を返すようになりました。

shutil.move(src, dst)

再帰的にファイルやディレクトリ (src) を別の場所 (dst) へ移動します。

移動先が存在するディレクトリの場合、 src はそのディレクトリの中へ移動します。移動先が存在していてそれがディレクトリでない場合、 os.rename() の動作によっては上書きされることがあります。

もし移動先が現在のファイルシステム上であれば os.rename() を使います。そうでない場合は src を(shutil.copy2() で) dst にコピーし、その後コピー元は削除されます。

バージョン 2.3 で追加.

exception shutil.Error

この例外は複数ファイルの操作を行っているときに生じる例外をまとめたものです。 copytree() に対しては例外の引数は3つのタプル(srcname, dstname, exception)からなるリストです。

バージョン 2.3 で追加.

10.10.1.1. copytree の例

以下は前述の copytree() 関数のドキュメント文字列を省略した実装例です。本モジュールで提供される他の関数の使い方を示しています。

def copytree(src, dst, symlinks=False, ignore=None):
    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks, ignore)
            else:
                copy2(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error as err:
            errors.extend(err.args[0])
    try:
        copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError as why:
        errors.extend((src, dst, str(why)))
    if errors:
        raise Error(errors)

ignore_patterns() ヘルパ関数を利用する、もう1つの例です。

from shutil import copytree, ignore_patterns

copytree(source, destination, ignore=ignore_patterns('*.pyc', 'tmp*'))

この例では、 .pyc ファイルと、 tmp で始まる全てのファイルやディレクトリを除いて、全てをコピーします。

ignore 引数にロギングさせる別の例です。

from shutil import copytree
import logging

def _logpath(path, names):
    logging.info('Working in %s' % path)
    return []   # nothing will be ignored

copytree(source, destination, ignore=_logpath)

10.10.2. アーカイブ化操作

圧縮とアーカイブ化されているファイルの読み書きの高水準なユーティリティも提供されています。これらは zipfiletarfile モジュールに依拠しています。

shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]])

アーカイブファイル (zip や tar など) を作成し、その名前を返します。

base_name は作成するファイルの名前で、パスを含み、フォーマットごとの拡張子を抜いたものです。 format はアーカイブフォーマットで “zip” (zlib モジュールもしくは外部の zip 実行可能ファイルが利用可能な場合), “tar”, “gztar” (zlib モジュールが利用可能な場合), “bztar” (bz2 モジュールが利用可能な場合) のいずれかです。

root_dir は、アーカイブのルートディレクトリとなるディレクトリです。すなわち、一般的には、アーカイブを作成する前に root_dir をカレントディレクトリにします。

base_dir は、アーカイブを開始するディレクトリです。すなわち、 base_dir は、アーカイブのすべてのファイルとディレクトリに共通する接頭辞になります。

root_dirbase_dir のどちらも、デフォルトはカレントディレクトリです。

ownergroup は、tar アーカイブを作成するときに使われます。デフォルトでは、カレントのオーナとグループを使います。

loggerPEP 282 に互換なオブジェクトでなければなりません。これは普通は logging.Logger のインスタンスです。

バージョン 2.7 で追加.

shutil.get_archive_formats()

アーカイブ化をサポートしているフォーマットのリストを返します。返されるシーケンスのそれぞれの要素は、タプル (name, description) です。

デフォルトでは、 shutil はこれらのフォーマットを提供しています:

  • zip: ZIP ファイル (zlib モジュールもしくは外部の zip 実行可能ファイルが利用可能な場合)。

  • tar: 圧縮されていない tar ファイル。

  • gztar: gzip で圧縮された tar ファイル (zlib モジュールが利用可能な場合)。

  • bztar: bzip2 で圧縮された tar ファイル (bz2 モジュールが利用可能な場合)。

register_archive_format() を使って、新しいフォーマットを登録したり、既存のフォーマットに独自のアーカイバを提供したりできます。

バージョン 2.7 で追加.

shutil.register_archive_format(name, function[, extra_args[, description]])

フォーマット name のアーカイバを登録します。 function は、アーカイバを呼び出すのに使われる呼び出し可能オブジェクトです。

extra_args は、与えられるなら (name, value) のシーケンスで、アーカイバ呼び出し可能オブジェクトが使われるときの追加キーワード引数に使われます。

description は、アーカイバのリストを返す get_archive_formats() で使われます。デフォルトでは、空のリストです。

バージョン 2.7 で追加.

shutil.unregister_archive_format(name)

アーカイブフォーマット name を、サポートされているフォーマットのリストから取り除きます。

バージョン 2.7 で追加.

10.10.2.1. アーカイブ化の例

この例では、ユーザの .ssh ディレクトリにあるすべてのファイルを含む、 gzip された tar ファイルアーカイブを作成します:

>>> from shutil import make_archive
>>> import os
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
>>> make_archive(archive_name, 'gztar', root_dir)
'/Users/tarek/myarchive.tar.gz'

結果のアーカイブは、以下のものを含みます:

$ tar -tzvf /Users/tarek/myarchive.tar.gz
drwx------ tarek/staff       0 2010-02-01 16:23:40 ./
-rw-r--r-- tarek/staff     609 2008-06-09 13:26:54 ./authorized_keys
-rwxr-xr-x tarek/staff      65 2008-06-09 13:26:54 ./config
-rwx------ tarek/staff     668 2008-06-09 13:26:54 ./id_dsa
-rwxr-xr-x tarek/staff     609 2008-06-09 13:26:54 ./id_dsa.pub
-rw------- tarek/staff    1675 2008-06-09 13:26:54 ./id_rsa
-rw-r--r-- tarek/staff     397 2008-06-09 13:26:54 ./id_rsa.pub
-rw-r--r-- tarek/staff   37192 2010-02-06 18:23:10 ./known_hosts