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()" を参照してください。もし、 *src* と
   *dst* が同じファイルであれば、 "Error" 例外が発生します。コピー先は
   書き込み可能である必要があります。そうでなければ "IOError" を発生し
   ます。もし *dst* が存在したら、置き換えられます。キャラクタやブロッ
   クデバイス、パイプ等の特別なファイルはこの関数ではコピーできません
   。 *src* と *dst* にはパス名を文字列で与えられます。

shutil.copymode(src, dst)

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

shutil.copystat(src, dst)

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

shutil.copy(src, dst)

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

shutil.copy2(src, dst)

   Identical to "copy()" except that "copy2()" also attempts to
   preserve file metadata.

   "copy2()" uses "copystat()" to copy the file metadata. Please see
   "copystat()" for more information.

shutil.ignore_patterns(*patterns)

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

   バージョン 2.6 で追加.

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

   *src* を起点としたディレクトリツリーをコピーします。 *dst* で指定さ
   れたターゲットディレクトリは、既存のもので無い必要があります。存在
   しない親ディレクトリも含めて作成されます。パーミッションと時刻は
   "copystat()" 関数でコピーされます。個々のファイルは
   "shutil.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
   番目のパラメータ *path* は *function* へ渡されたパス名です。 3番目
   のパラメータ *excinfo* は "sys.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. アーカイブ化操作
=========================

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

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_dir* と *base_dir* のどちらも、デフォルトはカレントディレクト
   リです。

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

   *logger* は **PEP 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
