Python で「UnicodeDecodeError」を解消できずファイルが読めない
テキストモードでファイルを開く際の既定エンコーディングが実ファイルと違うことが原因。
open() に encoding 引数を明示するか、バイナリモードで読んで自前デコードすると解決する。
公開:
要約
Python で UnicodeDecodeError: 'utf-8' codec can't decode byte ... などが出る場合、ファイルの実エンコーディングと open() が想定するエンコーディングが食い違っている。open(path, encoding='utf-8') のように明示的に指定する、または utf-8-sig / cp932 などファイル実態に合わせれば解消する。
よくある原因
- encoding 未指定:
open(path)だけだと OS のロケールに依存する。
Windows では cp932(Shift_JIS 系)、Linux では UTF-8 であることが多い。 - BOM 付き UTF-8: Excel で保存した CSV などは BOM が先頭に付き、
utf-8で読むと最初の文字に余計なバイトが残ることがある。 - エンコーディング誤認: 古い Windows 由来の文書を utf-8 として開いてしまう。
- 破損バイト: ネットワーク越しのバイナリ混入や、途中で切れたファイルで一部のバイト列が無効。
解決策
1. encoding を明示する
ほぼ全ての UnicodeDecodeError はこれで防げる。
with open("data.txt", encoding="utf-8") as f:
text = f.read()open() の仕様 のとおり、テキストモードで encoding を省略するとロケール既定が使われる。
2. BOM 付き UTF-8 は utf-8-sig
import csv
with open("export.csv", encoding="utf-8-sig") as f:
rows = list(csv.reader(f))utf-8-sig は読み込み時に BOM を取り除き、書き込み時には先頭に付与する。
3. Shift_JIS / cp932
Windows のメモ帳で保存した古いファイルは cp932 が安全。
with open("legacy.txt", encoding="cp932") as f:
text = f.read()shift_jis ではなく cp932 を推奨(NEC 拡張・IBM 拡張文字を含むため)。
4. errors 引数で握り潰す
ログのような壊れても致命的でないファイルなら、errors='replace' でデコードできないバイトを U+FFFD(�)に置き換えられる(? への置換はエンコード時の挙動で、デコード時は �)。
with open("noisy.log", encoding="utf-8", errors="replace") as f:
text = f.read()5. バイナリモードで読み自前デコード
判別が必要なら chardet や charset-normalizer でエンコーディングを推定して decode する。
import charset_normalizer
raw = open("unknown.txt", "rb").read()
guess = charset_normalizer.from_bytes(raw).best()
text = str(guess)実行例
実際に上記の手順を python:3.12(Debian GNU/Linux 13 trixie)環境で動かすと、cp932 で用意したファイルを encoding 未指定で開いた段階で UnicodeDecodeError: 'utf-8' codec can't decode byte 0x93 が発生し、encoding='cp932' を明示することで正常に読み出せることが確認できる。
== versions ==
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
Python 3.12.13
git version 2.47.3
== run ==
--- cp932(Shift_JIS) で日本語ファイルを用意 ---
--- utf-8 で読む (UnicodeDecodeError を想定)---
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x93 in position 0: invalid start byte
終了コード: 1
--- 解消1: encoding=cp932 を明示する ---
日本語テキスト
--- 解消2: errors=replace で壊れたバイトを握り潰す ---
'���{��e�L�X�g\n'
--- 参考: BOM 付き UTF-8 は utf-8-sig で先頭 BOM を除去 ---
utf-8-sig: 'hello'
utf-8 : '\ufeffhello'— 2026-06-12 時点の出力