目次

前のトピックへ

10.9. linecache — テキストラインにランダムアクセスする

次のトピックへ

10.11. dircache — キャッシュされたディレクトリ一覧の生成

このページ

10.10. shutil — 高レベルなファイル操作

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

参考

Latest version of the shutil module Python source code

警告

高レベルなファイルコピー関数(copy(), 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 は完全なターゲットファイル名である必要があります。コピー先にディレクトリ名を使用したい場合は、 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)

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

shutil.ignore_patterns(*patterns)

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

バージョン 2.6 で追加.

shutil.copytree(src, dst[, symlinks])

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

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

ignore 引数を利用する場合、その呼び出し可能オブジェクトは、引数として、 copytree() が走査するディレクトリと、 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)

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

もし移動先が現在のファイルシステム上であれば単純に名前を変更します。そうでない場合は(copy2() で)コピーを行い、その後コピー元は削除されます。

バージョン 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), why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error, err:
            errors.extend(err.args[0])
    try:
        copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError, 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. アーカイブの操作

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

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

base_name は作成するファイルの名前で、パスを含み、フォーマット特有の拡張子はすべて除きます。 format はアーカイブフォーマットで、 “zip”, “tar”, “bztar” または “gztar” のいずれかです。

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

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

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

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

バージョン 2.7 で追加.

shutil.get_archive_formats()

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

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

  • gztar: gzip された tar ファイル
  • bztar: bzip2 された tar ファイル
  • tar: 圧縮されていない tar ファイル
  • zip: ZIP ファイル

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