Python TemporaryFileとNamedTemporaryFileの違い|パスが取れない理由とWindowsでの動き

tempfile.TemporaryFile()は「名前(パス)を持たない一時ファイル」を作り、NamedTemporaryFile()は「パスのある一時ファイル」を作ります。自分のコードの中で書いて読むだけならTemporaryFile、パスを外部のコマンドや関数に渡したいならNamedTemporaryFileを選びます。

「TemporaryFileでパスを取りたい」「nameが数字になる」「Windowsだと動きが違う」といった疑問は、この名前の有無で説明できます。この記事では、両者の違いをmacOS上のPython 3.14で実際に動かして確かめ、tempfileモジュールの公式ドキュメント(2026年10月18日確認)の記述と合わせて整理します。tempfileモジュール全体の使い方は「Python tempfileとは?」で解説しています。

TemporaryFileとNamedTemporaryFileの違い(早見表)

項目 TemporaryFile() NamedTemporaryFile()
ファイルのパス ない(POSIX環境) ある(f.name)
name属性の中身 ファイルディスクリプタの番号(整数) フルパスの文字列
フォルダに見えるか 見えない 見える
別のプロセスから開く できない できる
削除のタイミング 閉じたとき 閉じたとき(delete・delete_on_closeで変更可)
Windowsでの動き NamedTemporaryFileの別名として動く 同じ
向いている用途 自分で書いて自分で読む作業用 外部コマンドやライブラリにパスを渡す

実際に比べる|フォルダに名前が残るか

同じ作業用フォルダの中に、TemporaryFileとNamedTemporaryFileを1つずつ作り、フォルダの中身を見てみます。

import os, tempfile

work = tempfile.mkdtemp()

with tempfile.TemporaryFile(mode="w+", encoding="utf-8", dir=work) as f:
    f.write("名前なし")
    f.seek(0)
    print("読み戻し:", f.read())
    print("name属性:", repr(f.name))
    print("フォルダの中身:", os.listdir(work))

with tempfile.NamedTemporaryFile(mode="w+", encoding="utf-8", dir=work, suffix=".txt") as g:
    print("name属性:", os.path.basename(g.name))
    print("フォルダの中身:", os.listdir(work))

print("閉じたあと:", os.listdir(work))
os.rmdir(work)

実行結果(macOS、Python 3.14。ファイル名は実行のたびに変わります):

読み戻し: 名前なし
name属性: 3
フォルダの中身: []
name属性: tmpmrb9et6w.txt
フォルダの中身: ['tmpmrb9et6w.txt']
閉じたあと: []

TemporaryFileは開いて読み書きできているのに、フォルダには何も見えません。nameも3という整数で、これはOSがファイルに割り当てた番号(ファイルディスクリプタ)です。一方のNamedTemporaryFileは、tmpで始まるファイルがフォルダに現れ、閉じると消えました。

公式ドキュメントでは、Unix系ではTemporaryFileのディレクトリエントリ(ファイル名)は作られないか、作成直後に削除されると説明されています。Linuxでは、使える場合はos.O_TMPFILEフラグで最初から名前のないファイルを作ります(Linuxカーネル3.11以降)。

TemporaryFileでパスを取得したいときは

結論として、POSIX環境のTemporaryFileからパスを取り出す方法はありません。そもそもパスが存在しないからです。「パスを渡したい」という要件が出てきた時点で、NamedTemporaryFileに切り替えます。

たとえば、一時ファイルにPythonスクリプトを書き、別プロセスで実行する場合です。Python 3.12で追加されたdelete_on_close=Falseを使うと、いったん閉じてもwithブロックを抜けるまではファイルが残ります。

import tempfile, subprocess, sys

with tempfile.NamedTemporaryFile("w", encoding="utf-8", suffix=".py", delete_on_close=False) as f:
    f.write('print("別プロセスから読めました")\n')
    f.close()   # ここではまだ消えない
    out = subprocess.run([sys.executable, f.name], capture_output=True, text=True)
    print(out.stdout.strip())
import os
print("withを抜けたあと存在するか:", os.path.exists(f.name))

実行結果:

別プロセスから読めました
withを抜けたあと存在するか: False

書き込みを確実にファイルへ反映させるため、別プロセスに渡す前にclose()しています。NamedTemporaryFileのdeleteとdelete_on_closeの組み合わせは「Python NamedTemporaryFileとは?」で詳しく扱っています。

WindowsではTemporaryFileも名前を持つ

公式ドキュメントには「POSIXでもCygwinでもないプラットフォームでは、TemporaryFileはNamedTemporaryFileの別名」と書かれています。つまりWindowsでTemporaryFileを使うと、実際には名前のある一時ファイルが作られ、nameにはパスが入ります。

ここから2つの注意点が出てきます。

  • Windowsで「nameがパスだから」とTemporaryFileのパスを外部に渡すコードを書くと、macOSやLinuxでは動かなくなる。パスを使うなら最初からNamedTemporaryFileにする
  • 「名前がないから他のプロセスから見えない」という性質は、Windowsでは成り立たない

どのOSでも同じ動きにしたいなら、「パスが要るかどうか」で関数を選び分けるのが安全です。

TemporaryFileでよくあるつまずき

TemporaryFileの既定のモードは"w+b"(バイナリの読み書き)です。ここで3つのつまずきが起きます。

import tempfile
with tempfile.TemporaryFile() as f:
    try:
        f.write("文字列")
    except TypeError as e:
        print("TypeError:", e)
with tempfile.TemporaryFile("w", encoding="utf-8") as f:
    f.write("abc")
    f.seek(0)
    try:
        f.read()
    except Exception as e:
        print(type(e).__name__ + ":", e)
with tempfile.TemporaryFile("w+", encoding="utf-8") as f:
    f.write("abc")
    print("seekなし:", repr(f.read()))
    f.seek(0)
    print("seek(0)後:", repr(f.read()))

実行結果:

TypeError: a bytes-like object is required, not 'str'
UnsupportedOperation: not readable
seekなし: ''
seek(0)後: 'abc'
症状 原因 直し方
TypeError: a bytes-like object is required 既定のバイナリモードに文字列を書いた mode="w+", encoding="utf-8"を指定するか、bytesを書く
UnsupportedOperation: not readable "w"は書き込み専用 "w+"にする
読んでも空文字が返る 書いた直後は位置が末尾にある f.seek(0)で先頭に戻す

位置の考え方は「Python seek()とは?」で解説しています。

使いどころ|メモリに載せたくないが残す必要もないデータ

TemporaryFileが向いているのは、「全部メモリに持つには大きいが、作業が終われば不要」なデータです。

import tempfile

def count_lines(rows):
    with tempfile.TemporaryFile(mode="w+", encoding="utf-8") as f:
        for r in rows:
            f.write(f"{r}\n")
        f.seek(0)
        return sum(1 for _ in f)

print(count_lines(range(100000)))

実行結果:

100000

名前がないので、他のプロセスに中身をのぞかれたり、同じ名前のファイルとぶつかったりする心配がありません。後片付けのコードも不要です。

SpooledTemporaryFile|小さいうちはメモリで済ませる

データが小さいことが多いなら、SpooledTemporaryFileも候補です。公式ドキュメントによると、サイズがmax_sizeを超えるかfileno()が呼ばれるまではメモリ上で動き、そのあとはTemporaryFileと同じようにディスクで動きます。rollover()を呼ぶと明示的にディスクへ移せます。

import tempfile

with tempfile.SpooledTemporaryFile(max_size=10, mode="w+", encoding="utf-8") as f:
    f.write("短い")
    print("ディスクに移ったか:", f._rolled)
    f.write("x" * 100)
    print("max_sizeを超えた後:", f._rolled)
    f.seek(0)
    print("中身の先頭:", f.read()[:6])

with tempfile.SpooledTemporaryFile(max_size=1000) as g:
    g.write(b"abc")
    g.rollover()          # 公開メソッドで明示的にディスクへ移す
    print("rollover()後:", g._rolled)

実行結果:

ディスクに移ったか: False
max_sizeを超えた後: True
中身の先頭: 短いxxxx
rollover()後: True

_rolledは動きを確かめるために見た内部の属性で、公開された機能ではありません。実際のコードでは参照しないでください。最初からメモリだけで済むと分かっているなら、BytesIOのほうが簡単です。

どれを使うか|4つの選び分け

やりたいこと 使うもの
自分で書いて自分で読むだけ TemporaryFile()
小さいことが多いが、たまに大きい SpooledTemporaryFile()
パスを外部コマンドやライブラリに渡す NamedTemporaryFile()
複数のファイルをまとめて置く TemporaryDirectory()

削除のタイミングを自分で管理したい場合は、mkstemp()・mkdtemp()を使います。

よくある質問

Q. TemporaryFileでファイルのパスを取得できますか?

macOSやLinuxなどPOSIX環境ではできません。name属性はパスではなくファイルディスクリプタの番号(整数)になります。パスが必要ならNamedTemporaryFileを使ってください。

Q. TemporaryFileとNamedTemporaryFileはどちらを使えばよいですか?

自分のプログラムの中で書いて読むだけならTemporaryFile、ファイルのパスを別の関数や外部コマンドに渡す必要があるならNamedTemporaryFileです。

Q. WindowsでもTemporaryFileは名前のないファイルになりますか?

なりません。公式ドキュメントによると、POSIXでもCygwinでもない環境(Windowsなど)ではTemporaryFileはNamedTemporaryFileの別名として動くため、名前のある一時ファイルが作られます。

Q. TemporaryFileに書いた内容を読むと空になるのはなぜですか?

書き込んだ直後は読み書き位置がファイルの末尾にあるためです。f.seek(0)で先頭に戻してから読んでください。また、モードは「w」ではなく「w+」にしないと読み込めません。

Q. 一時ファイルはいつ削除されますか?

TemporaryFileは閉じたとき(withブロックを抜けたとき)に削除されます。POSIX環境では作成直後にディレクトリから名前が消えているため、プログラムが異常終了してもファイルが残りにくい作りです。

あわせて読みたい

対面・無料|東京・永田町で毎週土曜日13時

1回の参加で、プログラミングの構造がわかる

ゼロからはじめるPython入門講座

8年間・累計600回開催/これまで全国で2万人以上が参加

「やはり対面で聞けるのはとても気づきがあり、価値があると思います」

参加者の声

  • 本当に初心者からの講座です。プログラミングに触ったことがなくて大丈夫です
  • 対面だから、その場で聞けます。つまずいた所を持ち帰らずに解決できます
  • 講座は1時間。そのあとも残って学習を続けられ、講師にも質問できます
  • 独学で挫折した方も。糸口が見つかって、講座のあと会員になる方が多くいます

無料で参加する|開催日程を見る

参加費は無料です