رفع خطاهای پایتون

خطای UnicodeDecodeError در پایتون؛ codec can’t decode byte و فایل فارسی

خطای UnicodeDecodeError در پایتون؛ codec can't decode byte و فایل فارسی

🗓 آخرین به‌روزرسانی:

اگر با فایل‌های فارسی، CSVهای خروجی اکسل یا داده‌هایی از سیستم‌های قدیمی کار می‌کنید، احتمالاً با پیامی مثل UnicodeDecodeError: 'utf-8' codec can't decode byte روبه‌رو شده‌اید. این خطا یعنی فایل با یک کدگذاری (Encoding) ذخیره شده ولی پایتون سعی کرده آن را با کدگذاری دیگری بخواند.

معنی خطای UnicodeDecodeError در پایتون

فایل‌های متنی روی دیسک مجموعه‌ای از بایت‌ها هستند و Encoding تعیین می‌کند هر حرف با چه بایت‌هایی ذخیره شود. UTF-8 استاندارد امروزی است، اما فایل‌های فارسی قدیمی ویندوز اغلب با cp1256 (Windows-1256) ذخیره شده‌اند. اگر encoding را مشخص نکنید، پایتون از پیش‌فرض سیستم‌عامل استفاده می‌کند که در ویندوز ممکن است UTF-8 نباشد. UnicodeDecodeError یعنی بایت‌ها با قواعد encoding انتخاب‌شده سازگار نبوده‌اند.

علت‌های رایج این خطا

  • خواندن فایلی که با cp1256 یا latin-1 ذخیره شده، با encoding برابر utf-8.
  • مشخص نکردن encoding در open() و تکیه بر پیش‌فرض ویندوز.
  • باز کردن فایل باینری (تصویر، PDF، اکسل xlsx) در حالت متنی.
  • CSVهای خروجی اکسل که encoding متفاوتی دارند.

کد غلط و کد درست (با خروجی واقعی)

همه نمونه‌کدهای زیر با پایتون 3.13.5 اجرا شده‌اند و خروجی‌ها همان چیزی است که پایتون واقعاً نمایش می‌دهد.

مثال 1: خواندن فایل cp1256 با utf-8

❌ کد غلط:

with open("notes.txt", "w", encoding="cp1256") as f:
    f.write("\u0633\u0644\u0627\u0645")  # Persian word for hello

with open("notes.txt", encoding="utf-8") as f:
    print(f.read())

خروجی:

Traceback (most recent call last):
  File "/home/user/project/main.py", line 5, in <module>
    print(f.read())
          ~~~~~~^^
  File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd3 in position 0: invalid continuation byte

✅ کد درست:

with open("notes.txt", "w", encoding="cp1256") as f:
    f.write("\u0633\u0644\u0627\u0645")  # Persian word for hello

with open("notes.txt", encoding="cp1256") as f:
    print(ascii(f.read()))

خروجی:

'\u0633\u0644\u0627\u0645'

مثال 2: بایت‌های نامعتبر و پارامتر errors

❌ کد غلط:

data = b"Price: \xff100"
print(data.decode("utf-8"))

خروجی:

Traceback (most recent call last):
  File "/home/user/project/main.py", line 2, in <module>
    print(data.decode("utf-8"))
          ~~~~~~~~~~~^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 7: invalid start byte

✅ کد درست:

data = b"Price: \xff100"
print(data.decode("utf-8", errors="replace"))

خروجی:

Price: �100

راه‌حل قدم‌به‌قدم

  1. خط خطا و نام encoding داخل پیام را بخوانید.
  2. همیشه در open() پارامتر encoding="utf-8" را صریحاً بنویسید.
  3. اگر فایل از ویندوز یا اکسل قدیمی آمده، encodingهای cp1256 یا utf-8-sig را امتحان کنید.
  4. برای فایل‌های باینری از حالت "rb" یا کتابخانه مخصوص (مثل pandas برای xlsx) استفاده کنید.
  5. فقط وقتی از دست رفتن چند کاراکتر مهم نیست، از errors="replace" یا errors="ignore" استفاده کنید.

خواندن پیام UnicodeDecodeError و عیب‌یابی

UnicodeDecodeError یعنی پایتون بایت‌هایی را با یک کدگذاری (encoding) خوانده که با کدگذاری واقعی فایل یکی نیست. در ویندوز، open بدون encoding اغلب از cp1252 یا کدگذاری محلی استفاده می‌کند و فایل UTF-8 حاوی متن فارسی را نمی‌تواند بخواند. پیام خطا نام codec، بایت مشکل‌دار و موقعیت آن را نشان می‌دهد.

اگر پیام 'utf-8' codec can't decode byte است، فایل احتمالاً UTF-8 نیست و ممکن است cp1256 (عربی ویندوز) یا UTF-16 باشد. اگر codec دیگری ذکر شده، فقط encoding='utf-8' را صریح بنویسید. کد زیر نشان می‌دهد همان بایت‌ها با کدگذاری درست و غلط چه نتیجه‌ای می‌دهند.

خواندن بایت‌ها با کدگذاری درست و غلط

data = "café".encode("utf-8")
print("Bytes:", data)

try:
    data.decode("ascii")
except UnicodeDecodeError as error:
    print(type(error).__name__, "-", error.reason, "at", error.start)

print("utf-8:", data.decode("utf-8"))
print("replace:", data.decode("ascii", errors="replace"))

خروجی (اجراشده با Python 3.13):

Bytes: b'caf\xc3\xa9'
UnicodeDecodeError - ordinal not in range(128) at 3
utf-8: café
replace: caf��

قدم‌به‌قدم رفع UnicodeDecodeError

پیام خطا نام codec و بایت مشکل‌دار را می‌دهد؛ از همین دو سرنخ استفاده کنید.

  1. codec پیام را ببینید: اگر charmap یا cp1252 است، فقط encoding=’utf-8′ را صریح بنویسید.
  2. بایت مشکل‌دار را بررسی کنید: بایت‌هایی مثل 0xd3 یا 0xc7 در ابتدای متن، نشانه فایل فارسی با کدگذاری cp1256 است.
  3. چند بایت اول را چاپ کنید: open(path, ‘rb’).read(20) نشان می‌دهد فایل BOM دارد (utf-8-sig) یا UTF-16 است.
  4. کدگذاری را تشخیص دهید: کتابخانه charset-normalizer کدگذاری محتمل فایل‌های ناشناخته را پیشنهاد می‌کند.
  5. یک بار تبدیل کنید: فایل را با کدگذاری درست بخوانید و با UTF-8 ذخیره کنید تا مشکل تکرار نشود.

در پروژه‌های واقعی این خطا اغلب هنگام خواندن CSV خروجی اکسل، فایل‌های زیرنویس قدیمی یا لاگ‌های سرور رخ می‌دهد. یک قانون ساده بسیاری از این مشکلات را حذف می‌کند: هر جا فایل متنی را باز می‌کنید، encoding را صریح بنویسید و همه فایل‌های پروژه را با UTF-8 ذخیره کنید. اگر داده از منبع بیرونی می‌آید، کدگذاری آن را در مستندات منبع بررسی کنید و همان را در کد ثبت کنید. این کار در تیم‌های چندنفره و سیستم‌عامل‌های مختلف از دردسرهای تکراری جلوگیری می‌کند.

چک‌لیست پیشگیری

  • در همه open ها پارامتر encoding='utf-8' را صریح بنویسید.
  • در pandas از pd.read_csv(path, encoding='utf-8') و برای فایل‌های اکسل‌ساخته از utf-8-sig استفاده کنید.
  • فایل‌ها را در ویرایشگر با UTF-8 ذخیره کنید و کدگذاری را در نوار پایین بررسی کنید.
  • برای فایل‌های ناشناخته، کتابخانه charset-normalizer کدگذاری محتمل را تشخیص می‌دهد.
  • errors='replace' را فقط برای دیدن داده بدون توقف به کار ببرید، نه برای داده نهایی.

📌 همچنین بخوانید: خطای unexpected EOF while parsing در پایتون، خطای ‘int’ object is not subscriptable در پایتون و خطای ImportError

سؤالات متداول

بهترین encoding برای فایل‌های فارسی چیست؟

UTF-8. فایل‌های جدید را همیشه با encoding="utf-8" بنویسید و بخوانید. برای CSVی که قرار است در اکسل باز شود، utf-8-sig مناسب است.

فرق UnicodeDecodeError و UnicodeEncodeError چیست؟

Decode یعنی تبدیل بایت به متن (هنگام خواندن)؛ Encode یعنی تبدیل متن به بایت (هنگام نوشتن یا چاپ). هر دو از ناسازگاری encoding ناشی می‌شوند.

در pandas چطور encoding را تعیین کنم؟

در pd.read_csv("file.csv", encoding="utf-8") یا در صورت نیاز encoding="cp1256" را بنویسید.

utf-8-sig چه فرقی با utf-8 دارد؟

utf-8-sig کاراکتر BOM ابتدای فایل را که اکسل و نوت‌پد اضافه می‌کنند حذف می‌کند؛ برای CSV های خروجی اکسل انتخاب مناسبی است.

فایل فارسی قدیمی با utf-8 باز نمی‌شود، چه کنم؟

احتمالاً با cp1256 ذخیره شده است. open(path, encoding='cp1256') را امتحان کنید و بعد فایل را با UTF-8 ذخیره کنید.

فرق UnicodeDecodeError و UnicodeEncodeError چیست؟

Decode هنگام تبدیل بایت به متن رخ می‌دهد و Encode هنگام تبدیل متن به بایت، مثلاً چاپ متن فارسی در کنسولی که از آن پشتیبانی نمی‌کند.

آموزش‌های مرتبط

آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *