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環境では作成直後にディレクトリから名前が消えているため、プログラムが異常終了してもファイルが残りにくい作りです。



