Python pathlibでファイルを作成・読み書き・削除する方法|touch・read_text・write_bytes・unlinkとPython 3.14のcopy/move

pathlibでは、空ファイルの作成はPath.touch()、テキストの読み書きはread_text()・write_text()、画像などバイナリの読み書きはread_bytes()・write_bytes()、削除はunlink()で行います。Python 3.14からはコピーのcopy()と移動のmove()も使えます。

この記事では、ファイル1つを作って、書いて、読んで、コピー・移動して、消すまでを、pathlibのメソッドだけで順番に試します。コードはPython 3.14.8で実行した結果です。2026年10月9日に公開されたPython 3.15で文字コードの初期値がUTF-8に変わった点も、あわせて説明します(2026年10月15日確認)。

メソッド早見表

やりたいことメソッド戻り値・注意点
空ファイルを作るtouch()既にあれば更新日時だけ変わる
フォルダを作るmkdir(parents=True, exist_ok=True)途中のフォルダもまとめて作る
テキストを書き込むwrite_text(data, encoding="utf-8")書いた文字数。既存ファイルは上書き
テキストを読むread_text(encoding="utf-8")ファイル全体の文字列
バイナリを書き込むwrite_bytes(data)書いたバイト数。strは渡せない
バイナリを読むread_bytes()bytes
追記・1行ずつ読むopen("a") / open()with文で使う
コピー・移動copy()・copy_into()・move()Python 3.14で追加
ファイルを削除unlink(missing_ok=True)フォルダには使えない
空のフォルダを削除rmdir()中身があるとエラー

各メソッドの仕様はpathlibの公式ドキュメントに基づいています(2026年10月15日確認)。

ファイルを作成する:touch()とmkdir()

from pathlib import Path

p = Path("work") / "memo.txt"
p.parent.mkdir(parents=True, exist_ok=True)
p.touch()
print(p, p.exists(), p.stat().st_size)
p.touch()  # 既にあってもエラーにならない
try:
    p.touch(exist_ok=False)
except FileExistsError as e:
    print("FileExistsError:", e)
work/memo.txt True 0
FileExistsError: [Errno 17] File exists: 'work/memo.txt'

パスは/演算子でつなげます。p.parentは親フォルダ(ここではwork)で、mkdir(parents=True, exist_ok=True)を付けると、途中のフォルダがなくてもまとめて作り、既にあってもエラーになりません。

touch()は、ファイルがなければ0バイトのファイルを作り、既にあれば更新日時を現在時刻にするだけで中身は消しません。「必ず新規に作りたい(既存なら止めたい)」ときはexist_ok=Falseを指定するとFileExistsErrorで知らせてくれます。なお、中身を書くならtouch()を挟まず、いきなりwrite_text()を呼んでもファイルは作られます。フォルダ作成と保存の組み合わせはフォルダを作成してファイルを保存する方法で詳しく扱っています。

テキストを書き込む・読む:write_text()とread_text()

p = Path("work/memo.txt")
n = p.write_text("1行目\n2行目\n", encoding="utf-8")
print(n)
print(repr(p.read_text(encoding="utf-8")))
print(p.read_text(encoding="utf-8").splitlines())
print(p.stat().st_size)
8
'1行目\n2行目\n'
['1行目', '2行目']
16

write_text()はファイルを開いて書き込み、閉じるところまでを1行で行います。戻り値は書き込んだ文字数(ここでは改行を含めて8文字)です。ファイルサイズが16バイトなのは、UTF-8では日本語1文字が3バイトになるためです。同じ名前のファイルがあると上書きされるので、追記したいときは後述のopen("a")を使います。

read_text()はファイル全体を1つの文字列で返します。行ごとのリストが欲しいときはsplitlines()を続けると、末尾の改行が取り除かれたリストになります。

encoding=”utf-8″は毎回書く

encodingを省略したときの文字コードは、Pythonのバージョンと環境で変わります。Python 3.14までは環境のロケールに従うため、日本語版Windowsでは多くの場合UTF-8以外(cp932)で読み書きされ、Macで作ったUTF-8のファイルを読むと文字化けやUnicodeDecodeErrorの原因になっていました。

2026年10月9日に公開されたPython 3.15では、encodingを省略した場合も環境によらずUTF-8を使うように変わりました(PEP 686、2026年10月15日確認)。ただし公式の説明でも、バージョン間で同じ動きにするにはencodingを明示するよう勧めています。古いPythonでも同じ結果になるよう、encoding="utf-8"は省略しないのが安全です。

省略している箇所は、-X warn_default_encodingを付けて実行すると警告で見つけられます。

$ python3 -X warn_default_encoding -c "from pathlib import Path; Path('work/memo.txt').read_text()"
<string>:1: EncodingWarning: 'encoding' argument not specified

バイナリを書き込む・読む:write_bytes()とread_bytes()

画像・PDF・ZIPのような文字ではないデータは、bytes型のままwrite_bytes()で書き、read_bytes()で読みます。次の例は、PNG画像の先頭8バイト(ファイル形式を示す決まった並び)を書き込んで読み返しています。

png_header = bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
b = Path("work/sample.bin")
print(b.write_bytes(png_header))
data = b.read_bytes()
print(data)
print(data[:4] == b"\x89PNG")
try:
    b.write_bytes("文字列")
except TypeError as e:
    print("TypeError:", e)
print(b.write_bytes("文字列".encode("utf-8")))
print(b.read_bytes().decode("utf-8"))
8
b'\x89PNG\r\n\x1a\n'
True
TypeError: memoryview: a bytes-like object is required, not 'str'
9
文字列

write_bytes()の戻り値は書き込んだバイト数です。文字列(str)をそのまま渡すとTypeErrorになるので、encode()でbytesに変換してから渡します。読み込んだbytesはdecode()で文字列に戻せます。ファイルのコピーだけが目的なら、dst.write_bytes(src.read_bytes())と書くこともできますが、大きなファイルでは全体をメモリに載せることになるため、次に紹介するcopy()のほうが向いています。

追記する・1行ずつ読む:open()

write_text()は常に上書きなので、ログのように末尾に足していくときはopen()を使います。使い方は組み込みのopen()と同じです。

p = Path("work/memo.txt")
with p.open("a", encoding="utf-8") as f:
    f.write("3行目(追記)\n")
with p.open(encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        print(i, line.rstrip("\n"))
1 1行目
2 2行目
3 3行目(追記)

モード"a"はファイルの末尾に書き足します。読むときにfor line in fと書くと1行ずつ取り出すので、ファイル全体を一度にメモリへ読み込むread_text()より、大きなログファイルに向いています。

コピー・移動する:copy()・copy_into()・move()(Python 3.14以降)

これまでpathlibにはコピーのメソッドがなく、shutil.copy()を使う必要がありました。Python 3.14でcopy()・copy_into()・move()・move_into()が追加されています。

src = Path("work/memo.txt")
try:
    src.copy(Path("backup/memo_copy.txt"))
except FileNotFoundError as e:
    print("FileNotFoundError:", e)

Path("backup").mkdir(exist_ok=True)
dst = src.copy(Path("backup/memo_copy.txt"))
print(dst, dst.exists())
into = src.copy_into(Path("backup"))
print(into)
moved = dst.move(Path("backup/memo_old.txt"))
print(moved, dst.exists(), moved.exists())
print(sorted(x.name for x in Path("backup").iterdir()))
FileNotFoundError: [Errno 2] No such file or directory: 'backup/memo_copy.txt'
backup/memo_copy.txt True
backup/memo.txt
backup/memo_old.txt False True
['memo.txt', 'memo_old.txt']
  • copy(コピー先のパス):ファイル名まで指定してコピーします。コピー先のフォルダがないとFileNotFoundErrorになるので、先にmkdir()しておきます。
  • copy_into(フォルダ):同じファイル名のまま、既存のフォルダの中へコピーします。
  • move(移動先のパス):移動(名前の変更を含む)です。移動先に同名のファイルがあると上書きされます。

どれも新しい場所を指すPathを返します。Python 3.13以前では使えないので、古い環境も対象にするコードではshutil.copy2()やshutil.move()を使ってください(shutil.move()の使い方)。

ファイルを削除する:unlink()とrmdir()

p = Path("work/sample.bin")
p.unlink()
print(p.exists())
try:
    p.unlink()
except FileNotFoundError as e:
    print("FileNotFoundError:", e)
p.unlink(missing_ok=True)
print("missing_ok=True ならエラーにならない")

d = Path("backup")
try:
    d.rmdir()
except OSError as e:
    print(type(e).__name__, e)
for f in d.iterdir():
    f.unlink()
d.rmdir()
print(d.exists())
False
FileNotFoundError: [Errno 2] No such file or directory: 'work/sample.bin'
missing_ok=True ならエラーにならない
OSError [Errno 66] Directory not empty: 'backup'
False

unlink()はファイルを削除します。ゴミ箱には入らず、元に戻せません。存在しないファイルに使うとFileNotFoundErrorになりますが、missing_ok=Trueを付けると何もせずに終わります。「あれば消す」処理はこれ1行で書けます。

フォルダはunlink()では消せず、rmdir()を使います。rmdir()は空のフォルダしか削除できないので、上の例では中のファイルを先に消しています(エラー番号66はmacOSの場合で、Linuxでは39になります)。中身ごとフォルダを消すshutil.rmtree()は確認なしで全部を削除するため、対象のパスをprint()で確かめてから使ってください。存在確認の方法はファイル・フォルダの存在確認をする方法にまとめています。

ファイル名・サイズ・更新日時を調べる

import datetime

p = Path("work/memo.txt")
st = p.stat()
print(p.name, p.stem, p.suffix, p.parent)
print(st.st_size, "bytes")
print(datetime.datetime.fromtimestamp(st.st_mtime).strftime("%Y-%m-%d"))
print(sorted(x.name for x in Path("work").iterdir()))
memo.txt memo .txt work
36 bytes
2026-10-15
['memo.txt']

nameはファイル名、stemは拡張子を除いた名前、suffixは拡張子です。stat()でサイズ(st_size)や更新日時(st_mtime)が取れます。フォルダ内のファイルをパターンで探すならglob()を使います(globの使い方)。相対パスと絶対パスの変換はrelative_to()とresolve()の記事で解説しています。

まとめ

  • 作成はtouch()、フォルダはmkdir(parents=True, exist_ok=True)
  • テキストはwrite_text()・read_text()。encoding="utf-8"を毎回書く
  • 画像などはwrite_bytes()・read_bytes()。strを渡すとTypeError
  • 追記と大きなファイルの1行ずつの読み込みはopen()
  • コピー・移動はPython 3.14以降ならcopy()・move()、それ以前はshutil
  • 削除はunlink(missing_ok=True)、空フォルダはrmdir()

ファイル操作は、業務の自動化でまず使う機能です。通学型プログラミングスクールのテックジムでは、自分のペースで課題を進め、つまずいたところはトレーナーに質問できます。まずは無料Python講座で試してみてください。

よくある質問

Q. write_text()で追記はできますか?

できません。write_text()は常に上書きします。追記したいときは、with p.open(“a”, encoding=”utf-8″) as f: でファイルを開いてf.write()を使います。

Q. write_bytes()とwrite_text()の違いは何ですか?

write_text()は文字列を文字コードに変換して書き込み、書いた文字数を返します。write_bytes()はbytesをそのまま書き込み、書いたバイト数を返します。画像やPDFなどにはwrite_bytes()を使います。

Q. touch()は既存のファイルの中身を消しますか?

消しません。既にファイルがある場合は更新日時が現在時刻に変わるだけです。exist_ok=Falseを指定すると、既存のファイルではFileExistsErrorになります。

Q. pathlibでファイルをコピーするには?

Python 3.14以降ならsrc.copy(dst)で、コピー先のパスを指定してコピーできます。3.13以前ではshutil.copy2(src, dst)を使います。

あわせて読みたい

学習の順序はPython学習のロードマップ、標準で使える機能の一覧はPython標準ライブラリのモジュール一覧にまとめています。

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら