Pythonのより高度なファイル、フォルダ操作ができるshutilモジュール その1:ファイルのコピー shutil.copyfileとフォルダのコピー shutil.copytree

  • URLをコピーしました!
目次

前回のおさらい

過去3回に渡って、osモジュールとshutilモジュールを比較するため、ファイル・フォルダ操作に関して解説をしています。

今回はとうとうshutilモジュールに関して解説を進めていきたいと思います。

まずはこれまでのおさらい。

これまでosモジュールを使って、フォルダの作成、フォルダ・ファイルの名前変更、移動、削除を行ってきました。

表にしてみるとこんな感じです。

osモジュール
フォルダの作成os.mkdir(“フォルダ名”)
フォルダ名の変更os.rename(“変更前”, “変更後”)
ファイル名の変更os.rename(“変更前”,”変更後”)
フォルダの移動os.rename(“変更前”,”変更後”)
ファイルの移動os.rename(“変更前”,”変更後”)
フォルダの削除os.rmdir(“フォルダ名”)
ファイルの削除os.rmove(“ファイル名”)

今回もファイル・フォルダ操作を行いますので、とりあえず最初にこんな感じでファイル・フォルダ構造を整えておきます。

document1.txtには1から5の数字を書いておいてください。

document2.txtは特に何も書いていない空のファイルでOKです。

この状態でos_module_test内で新しいPythonプログラムを作成します。

そして今回はshutilモジュールをインポートしてください。

import shutil

これで準備は完了です。

ファイルのコピー:shutil.copyfile(“コピー元”,”コピー先”)

ファイル・フォルダのコピーは実はosモジュールではなかった機能です。

(私が知らないだけかもしれませんが…)

まずはフォルダのコピーを紹介します。

フォルダのコピーはshutil.copyfile(“コピー元”,”コピー先”)でできます。

document1.txtをdocument3.txtとしてコピーしてみましょう。

shutil.copyfile("document1.txt", "document3.txt")

document1.txtには1から5の数字が書かれているので、コピー先であるdocument3.txtにも1から5の数字が書かれているはずです。

確認してみましょう。

確かに1から5の数字が書かれていて、コピーされたファイルだと分かりました。

ちなみに同じフォルダに同じファイル名でコピーしようとするとどうなるでしょうか。

shutil.copyfile("document1.txt", "document1.txt")

実行結果
---------------------------------------------------------------------------
SameFileError                             Traceback (most recent call last)
<ipython-input-7-c2cfe34d6f53> in <module>
----> 1 shutil.copyfile("document1.txt", "document1.txt")

/opt/anaconda3/lib/python3.7/shutil.py in copyfile(src, dst, follow_symlinks)
    102     """
    103     if _samefile(src, dst):
--> 104         raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
    105 
    106     for fn in [src, dst]:

SameFileError: 'document1.txt' and 'document1.txt' are the same file

同じファイルだということでコピーできないとエラーが出ました。

すでにあるファイル名をコピー先に指定してみる

ではすでにあるファイル名でコピーしようとするとどうなるでしょうか。

document3.txtを開いて中身を消した後、document1.txtをdocument3.txtとしてコピーしてみましょう。

shutil.copyfile("document1.txt", "document3.txt")

数字を消したはずなのに、1から5の数字が書かれています。

これはdocument1.txtがdocument3.txtに上書きされたということを示しています。

ということですでにあるファイル名をコピー先に指定すると上書きされます。

違うフォルダ間でコピー

コピー元、コピー先にはパスを含んだ形でもコピーできます。

document1.txtをfolder2の中にdocument1.txtとしてコピーしてみましょう。

shutil.copyfile("document1.txt", "./folder2/document1.txt")

前に解説した通り、folder2の前にある”./”は現在のファイルを示しています。

document1.txtがfolder2内にdocument1.txtとしてコピーされました。

フォルダをコピーしてみる

ファイルがコピーできるということで、フォルダはコピーできないのでしょうか。

folder1をfolder3としてコピーをしようとしてみます。

shutil.copyfile("folder1", "folder3")

実行結果
---------------------------------------------------------------------------
IsADirectoryError                         Traceback (most recent call last)
<ipython-input-9-bc8615ecadd5> in <module>
----> 1 shutil.copyfile("folder1", "folder3")

/opt/anaconda3/lib/python3.7/shutil.py in copyfile(src, dst, follow_symlinks)
    118         os.symlink(os.readlink(src), dst)
    119     else:
--> 120         with open(src, 'rb') as fsrc:
    121             with open(dst, 'wb') as fdst:
    122                 copyfileobj(fsrc, fdst)

IsADirectoryError: [Errno 21] Is a directory: 'folder1'

folder1はフォルダ(directory:ディレクトリ)だということでエラーが出てきました。

実はフォルダをコピーするには違うコマンドが存在するのです。

フォルダをコピーする方法:shutil.copytree(“コピー元”, “コピー先”)

フォルダをコピーするには、shutil.copytree(“コピー元”,”コピー先”)というコマンドを使用します。

ということでfolder1をfolder3としてコピーしてみましょう。

shutil.copytree("folder1", "folder3")

コピーすることができました。

ここで一つ疑問です。

前にos.rmdirでフォルダを削除しようとした際、空のフォルダなら削除できたのですが、中に何かファイルなどが存在する場合は削除できませんでした。

このshutil.copytreeも同じ様な制限はあるのでしょうか。

中身があるフォルダをコピーしてみる

ということで中身が入っているfolder2をfolder4としてコピーしてみましょう。

shutil.copytree("folder2", "folder4")

実行した結果、folder4が作られ、その中にfolder2と同じ様にdocument1.txtとdocument2.txtがあります。

ということでshutil.copytreeでは中にファイルがあろうがなかろうがコピーすることができるということです。

違うフォルダにコピーしてみる

前回、ファイルをコピーする際、コピー元やコピー先にはパスを含んだ形でも指定可能だとお話ししました。

ということでフォルダでも同じこととが可能なのか試してみましょう。

今回は先ほどfolder2からコピーしたfolder4を、さらにfolder3の中にfolder4としてコピーしてみます。

shutil.copytree("folder4", "./folder3/folder4")

folder3の中にfolder4が作成され、その中にdocument1.txtとdocument2.txtが存在する形になりました。

ということでコピー元、コピー先にパスを含んだ形でもコピーすることができます。

すでに存在するフォルダ名をコピー先に指定してみる

ではちょっと指定を間違えたとして、コピー先をすでにあるフォルダ名にしてしまった場合どうなるでしょうか。

現在、フォルダはfolder1、folder2、folder3、folder4があります。

そこでfolder1をfolder4としてコピーしてみます。

shutil.copytree("folder1", "folder4")

実行結果
---------------------------------------------------------------------------
FileExistsError                           Traceback (most recent call last)
<ipython-input-8-cc5938e3cc6e> in <module>
----> 1 shutil.copytree("folder1", "folder4")

/opt/anaconda3/lib/python3.7/shutil.py in copytree(src, dst, symlinks, ignore, copy_function, ignore_dangling_symlinks)
    322         ignored_names = set()
    323 
--> 324     os.makedirs(dst)
    325     errors = []
    326     for name in names:

/opt/anaconda3/lib/python3.7/os.py in makedirs(name, mode, exist_ok)
    219             return
    220     try:
--> 221         mkdir(name, mode)
    222     except OSError:
    223         # Cannot rely on checking for EEXIST, since the operating system

FileExistsError: [Errno 17] File exists: 'folder4'

ちょっと長いエラーが出てきてびっくりしましたが、要するにもうfolder4があるからコピーできないということです。

次回はshutilモジュールを使って、ファイルやフォルダを移動、名前を変更する方法を解説していきましょう。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる