できない.dev

Python で「UnicodeDecodeError」を解消できずファイルが読めない

テキストモードでファイルを開く際の既定エンコーディングが実ファイルと違うことが原因。
open() に encoding 引数を明示するか、バイナリモードで読んで自前デコードすると解決する。

#unicode#encoding#file-io#utf-8

公開:

要約

Python で UnicodeDecodeError: 'utf-8' codec can't decode byte ... などが出る場合、ファイルの実エンコーディングと open() が想定するエンコーディングが食い違っている。open(path, encoding='utf-8') のように明示的に指定する、または utf-8-sig / cp932 などファイル実態に合わせれば解消する。

よくある原因

  1. encoding 未指定: open(path) だけだと OS のロケールに依存する。
    Windows では cp932(Shift_JIS 系)、Linux では UTF-8 であることが多い。
  2. BOM 付き UTF-8: Excel で保存した CSV などは BOM が先頭に付き、utf-8 で読むと最初の文字に余計なバイトが残ることがある。
  3. エンコーディング誤認: 古い Windows 由来の文書を utf-8 として開いてしまう。
  4. 破損バイト: ネットワーク越しのバイナリ混入や、途中で切れたファイルで一部のバイト列が無効。

解決策

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. バイナリモードで読み自前デコード

判別が必要なら chardetcharset-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 時点の出力

この記事は役立ちましたか?