يظهر خطأ UnicodeDecodeError في Python عندما يحاول البرنامج تحويل بايتات إلى نص باستخدام encoding لا يطابق الترميز الفعلي للبيانات. فإذا كان الملف محفوظًا مثلًا بترميز مختلف عن utf-8 ثم قرأته على أنه UTF-8، قد ترى رسالة مثل 'utf-8' codec can't decode byte. الحل الصحيح هو تحديد ترميز الملف واستخدامه عند القراءة، وليس تجربة ترميزات عشوائية فقط لإخفاء الخطأ.
في هذا المقال من سلسلة مشكلة وحل في بايثون على بايثون العرب ستتعلم معنى رسالة UnicodeDecodeError، وما المقصود بـ codec can't decode byte وinvalid start byte وcharmap، ثم كيفية اختيار encoding الصحيح عند قراءة الملفات النصية وملفات CSV، بما فيها بعض الملفات العربية وملفات Windows.
الفكرة ببساطة: خطأ UnicodeDecodeError يعني أن Python لم يستطع فك بعض البايتات إلى نص باستخدام الترميز الذي تم اختياره للقراءة.
شكل الخطأ
قد يظهر الخطأ بأكثر من صيغة. من أشهر الرسائل:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x... in position ...
وقد يظهر أيضًا بهذا الشكل على Windows:
UnicodeDecodeError: 'charmap' codec can't decode byte 0x... in position ...
أو عند قراءة ملف CSV:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 10: invalid start byte
رغم أن الرسائل تبدو معقدة، إلا أن معناها بسيط: Python لم يستطع فك البايتات باستخدام الترميز الذي استُخدم للقراءة.
ماذا تعني رسالة codec can't decode byte؟
عندما ترى رسالة مثل UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 10: invalid start byte، فكل جزء منها يعطيك معلومة مفيدة عن المشكلة:
'utf-8' codec: الترميز الذي حاول Python استخدامه لفك البايتات.byte 0x81: أحد البايتات التي لم يستطع هذا الترميز تفسيرها في ذلك الموضع.position 10: موضع تقريبي للمشكلة داخل البيانات.invalid start byte: البايت الموجود في هذا الموضع لا يصلح كبداية لتسلسل UTF-8 صحيح؛ وغالبًا يعني أن البيانات ليست UTF-8 أصلًا، أو أنك تقرأ بيانات غير نصية كأنها نص.
أما رسالة 'charmap' codec can't decode byte فتظهر غالبًا عندما تُقرأ البيانات بترميز محلي يعتمد على النظام بدل الترميز الفعلي للملف. على Windows قد يكون الترميز الافتراضي صفحة ترميز محلية، لذلك إذا كنت تعرف أن الملف UTF-8 فمن الأفضل تحديد encoding="utf-8" صراحة.
مثال يسبب UnicodeDecodeError
لنفترض أن لديك ملفًا اسمه students.csv يحتوي على أسماء عربية، لكنه محفوظ بترميز مختلف عن utf-8. ثم كتبت الكود التالي:
with open("students.csv", "r", encoding="utf-8") as file:
content = file.read()
print(content)
إذا كان الملف غير محفوظ بترميز utf-8، فقد يظهر خطأ UnicodeDecodeError.
ما معنى UnicodeDecodeError؟
لفهم الخطأ، نحتاج إلى تبسيط الفكرة. الملفات داخل الكمبيوتر لا تُخزن كأحرف مباشرة، بل تُخزن كبايتات. وعندما يقرأ Python الملف كنص، يحتاج إلى معرفة الطريقة الصحيحة لتحويل هذه البايتات إلى أحرف.
هذه الطريقة تسمى encoding أو الترميز.
إذا كان الملف محفوظًا بترميز معين، وحاول Python قراءته بترميز آخر، قد يفشل التحويل وتظهر رسالة UnicodeDecodeError.
مثال مبسط:
- الملف محفوظ بترميز
cp1256. - أنت تحاول قراءته باستخدام
utf-8. - Python يجد بايتات لا يستطيع تفسيرها كـ UTF-8.
- فتظهر رسالة
UnicodeDecodeError.
ما هو encoding في Python؟
encoding هو الترميز المستخدم لقراءة أو كتابة النصوص داخل الملفات. إذا كنت تحتاج أساسيات فتح الملفات أولًا، راجع درس التعامل مع الملفات في Python. وعند فتح ملف نصي يمكنك تحديد الترميز هكذا:
open("file.txt", "r", encoding="utf-8")
أشهر الترميزات التي قد تصادفها:
| الترميز | متى يستخدم؟ | ملاحظة |
|---|---|---|
utf-8 |
الأكثر استخدامًا حاليًا | مناسب للعربية والإنجليزية ومعظم اللغات |
utf-8-sig |
ملفات UTF-8 التي تحتوي على BOM | مفيد لبعض ملفات Excel أو Windows |
cp1256 |
بعض الملفات العربية القديمة على Windows | قد يحل مشاكل ملفات عربية محفوظة كـ ANSI |
latin-1 |
بعض الملفات الغربية القديمة | يفك أي قيمة بايت تقريبًا دون خطأ، لكنه قد ينتج نصًا غير صحيح إذا لم يكن هذا ترميز الملف الحقيقي |
قاعدة مهمة: لا يوجد ترميز واحد يصلح لكل الملفات. الأفضل أن تعرف ترميز الملف أو تجرب الترميز المناسب حسب مصدر الملف.
السبب الأول: قراءة ملف بترميز خاطئ
هذا هو السبب الأشهر. يكون الملف محفوظًا بترميز معين، لكنك تقرأه بترميز مختلف.
مثال قد يسبب الخطأ:
with open("arabic_file.txt", "r", encoding="utf-8") as file:
text = file.read()
إذا كان الملف محفوظًا بترميز cp1256 مثلًا، جرّب:
with open("arabic_file.txt", "r", encoding="cp1256") as file:
text = file.read()
print(text)
إذا اختفى الخطأ وظهر النص العربي بشكل صحيح، فالمشكلة كانت في الترميز.
السبب الثاني: استخدام الترميز الافتراضي بدون تحديد encoding
بعض المبتدئين يفتحون الملف هكذا:
with open("data.txt", "r") as file:
content = file.read()
قد يعمل هذا أحيانًا، لكنه ليس أفضل أسلوب؛ لأن open() في الوضع النصي يستخدم ترميزًا افتراضيًا يعتمد على النظام والـ locale عندما لا تحدد encoding. لذلك قد يعمل الملف على جهاز ويفشل على جهاز آخر، وخصوصًا عند اختلاف إعدادات Windows أو Linux.
الأفضل أن تكتب الترميز صراحة:
with open("data.txt", "r", encoding="utf-8") as file:
content = file.read()
هذا يجعل الكود أوضح وأكثر قابلية للنقل بين الأجهزة.
السبب الثالث: ملف CSV صادر من Excel
كثير من مشاكل UnicodeDecodeError تظهر عند قراءة ملفات CSV تم تصديرها من Excel، خصوصًا إذا كانت تحتوي على نصوص عربية. وإذا كنت تحتاج شرح بنية CSV وقراءتها أولًا، فراجع درس ملفات CSV في Python.
ملف CSV الصادر من Excel قد يكون محفوظًا بأكثر من ترميز. إذا كان الملف UTF-8 مع BOM في بدايته، فاستخدام utf-8-sig يقرأ UTF-8 ويزيل علامة BOM من البداية تلقائيًا. أما إذا كان الملف محفوظًا أصلًا بترميز مختلف عن UTF-8، فلن يحوله utf-8-sig إلى UTF-8 ولن يكون حلًا عامًا للخطأ.
import csv
with open("students.csv", "r", encoding="utf-8-sig") as file:
reader = csv.reader(file)
for row in reader:
print(row)
إذا لم ينجح utf-8-sig، وكنت تتعامل مع ملف عربي قديم من Windows، جرّب cp1256.
with open("students.csv", "r", encoding="cp1256") as file:
content = file.read()
print(content)
السبب الرابع: محاولة قراءة ملف غير نصي كنص
أحيانًا يظهر الخطأ لأنك تحاول قراءة ملف ليس نصيًا أصلًا، مثل صورة أو ملف PDF أو ملف Excel بامتداد .xlsx باستخدام open() كنص.
مثال خاطئ:
with open("report.xlsx", "r", encoding="utf-8") as file:
content = file.read()
ملف .xlsx ليس ملفًا نصيًا بسيطًا مثل CSV، لذلك لا تقرأه بهذه الطريقة. إذا أردت التعامل مع Excel، استخدم مكتبة مناسبة مثل openpyxl.
الحل الأول: استخدم encoding="utf-8"
إذا كنت أنت من ينشئ الملف أو تتحكم في طريقة حفظه، اجعل الترميز utf-8 واستخدمه عند القراءة والكتابة.
كتابة ملف نصي بترميز UTF-8:
with open("message.txt", "w", encoding="utf-8") as file:
file.write("مرحبًا بك في بايثون العرب")
قراءة نفس الملف:
with open("message.txt", "r", encoding="utf-8") as file:
text = file.read()
print(text)
هذا هو الأسلوب الأفضل في المشاريع الجديدة.
الحل الثاني: استخدم utf-8-sig مع بعض ملفات CSV
استخدم utf-8-sig عندما تعرف أن الملف UTF-8 لكنه يحتوي على BOM في البداية؛ فهذا الترميز يتعامل مع UTF-8 ويزيل علامة BOM عند القراءة. لا تستخدمه باعتباره بديلًا عشوائيًا عن utf-8 إذا كان الملف محفوظًا بترميز مختلف أصلًا.
import csv
with open("data.csv", "r", encoding="utf-8-sig") as file:
reader = csv.DictReader(file)
for row in reader:
print(row)
هذا الحل مفيد عندما يكون الملف UTF-8 لكنه يحتوي على BOM في البداية.
الحل الثالث: استخدم cp1256 للملفات العربية القديمة
إذا كان الملف عربيًا وقديمًا أو محفوظًا من برنامج على Windows بصيغة ANSI، فقد يكون الترميز المناسب هو cp1256.
with open("arabic_data.txt", "r", encoding="cp1256") as file:
content = file.read()
print(content)
إذا ظهر النص العربي بشكل صحيح، فهذا يعني أن الترميز كان مناسبًا.
الحل الرابع: استخدام errors عند الحاجة
في بعض الحالات تريد قراءة الملف حتى لو كانت فيه أحرف غير قابلة للفهم. هنا يمكنك استخدام الخيار errors.
مثال باستخدام replace:
with open("data.txt", "r", encoding="utf-8", errors="replace") as file:
content = file.read()
print(content)
هذا يستبدل الأحرف غير المفهومة برمز بديل بدل إيقاف البرنامج.
ويمكنك أيضًا استخدام ignore:
with open("data.txt", "r", encoding="utf-8", errors="ignore") as file:
content = file.read()
لكن انتبه: استخدام ignore قد يحذف بعض الأحرف من النص، لذلك لا تستخدمه إلا عند الضرورة.
تحذير: خيار errors="ignore" قد يخفي المشكلة ويحذف أحرفًا من النص. الأفضل معرفة الترميز الصحيح بدل تجاهل الخطأ.
طريقة حل UnicodeDecodeError خطوة بخطوة
عندما يظهر الخطأ، اتبع هذه الخطوات بدل تجربة حلول عشوائية:
- اقرأ رسالة الخطأ نفسها: هل تذكر
utf-8أمcharmap؟ وهل يظهرinvalid start byte؟ - تأكد أن الملف نصي فعلًا وليس صورة أو PDF أو ملف
.xlsxيُقرأ كنص. - حدد مصدر الملف وترميزه إن أمكن؛ لا يوجد ترميز واحد صحيح لكل الملفات.
- إذا كان الملف محفوظًا فعلًا بصيغة UTF-8، استخدم
encoding="utf-8". - إذا كان UTF-8 ويحتوي على BOM، استخدم
encoding="utf-8-sig". - إذا كان ملفًا عربيًا قديمًا من Windows، فقد يكون
cp1256هو الترميز الصحيح. - إذا ظهرت رسالة
charmapعلى Windows وكنت تعرف أن الملف UTF-8، حددencoding="utf-8"صراحة بدل الاعتماد على الترميز الافتراضي. - استخدم
errors="replace"فقط للقراءة المؤقتة عند الحاجة؛ أماerrors="ignore"فقد يؤدي إلى فقد بيانات. - احفظ ملفات المشاريع الجديدة بترميز UTF-8 متى كان ذلك ممكنًا.
مثال عملي: قراءة CSV عربي بدون خطأ
لنفترض أن لديك ملفًا اسمه students.csv يحتوي على:
الاسم,المدينة
علي,عدن
سارة,صنعاء
جرّب أولًا قراءة الملف باستخدام UTF-8:
import csv
with open("students.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)
for row in reader:
print(row)
إذا كنت تعرف أن الملف UTF-8 لكنه يحتوي على BOM، استخدم utf-8-sig:
with open("students.csv", "r", encoding="utf-8-sig") as file:
reader = csv.reader(file)
for row in reader:
print(row)
وإذا كان الملف محفوظًا بترميز عربي قديم، جرّب:
with open("students.csv", "r", encoding="cp1256") as file:
reader = csv.reader(file)
for row in reader:
print(row)
استخدام try و except مع UnicodeDecodeError
يمكنك التعامل مع الخطأ باستخدام try و except حتى تعرض رسالة واضحة بدل توقف البرنامج.
try:
with open("data.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
except UnicodeDecodeError:
print("تعذر قراءة الملف بسبب مشكلة في الترميز.")
print("جرّب encoding='utf-8-sig' أو encoding='cp1256' حسب مصدر الملف.")
هذا لا يحل الترميز تلقائيًا، لكنه يجعل البرنامج أوضح للمستخدم.
تجربة أكثر من ترميز تلقائيًا
في بعض المشاريع البسيطة، يمكنك تجربة أكثر من ترميز حتى ينجح أحدها.
encodings = ["utf-8", "utf-8-sig", "cp1256"]
for enc in encodings:
try:
with open("data.txt", "r", encoding=enc) as file:
content = file.read()
print("تمت القراءة باستخدام:", enc)
print(content)
break
except UnicodeDecodeError:
print("فشل الترميز:", enc)
هذا المثال مفيد تعليميًا، لكنه لا يغني عن معرفة الترميز الصحيح للملف.
تحويل ملف إلى UTF-8
إذا عرفت أن ملفًا عربيًا محفوظ بترميز cp1256 وتريد تحويله إلى utf-8، يمكنك قراءته بالترميز القديم ثم كتابته من جديد بترميز UTF-8.
with open("old_file.txt", "r", encoding="cp1256") as file:
content = file.read()
with open("new_file_utf8.txt", "w", encoding="utf-8") as file:
file.write(content)
بهذا يصبح لديك ملف جديد بترميز UTF-8، وهو أسهل للتعامل معه لاحقًا.
الفرق بين UnicodeDecodeError و UnicodeEncodeError
قد ترى أحيانًا خطأ آخر اسمه UnicodeEncodeError. الفرق بينهما:
| الخطأ | متى يحدث؟ | المعنى |
|---|---|---|
UnicodeDecodeError |
عند قراءة ملف أو تحويل بايتات إلى نص | Python لم يستطع فك الترميز |
UnicodeEncodeError |
عند كتابة نص إلى ملف أو تحويل نص إلى بايتات | Python لم يستطع ترميز النص |
مقالنا هنا يركز على UnicodeDecodeError لأنه يظهر غالبًا عند قراءة الملفات.
مقارنة سريعة بين الحلول
| الحالة | الحل المقترح |
|---|---|
| ملف حديث أو أنت من أنشأته | encoding="utf-8" |
| ملف CSV من Excel وفيه مشكلة بداية الملف | encoding="utf-8-sig" |
| ملف عربي قديم من Windows | encoding="cp1256" |
| تريد قراءة الملف مؤقتًا رغم وجود أحرف مشكلة | errors="replace" |
| الملف ليس نصيًا مثل xlsx أو pdf | استخدم مكتبة مناسبة لنوع الملف |
أفضل ممارسات لتجنب UnicodeDecodeError
- حدد
encodingدائمًا عند قراءة وكتابة الملفات النصية. - استخدم
utf-8في المشاريع الجديدة قدر الإمكان. - استخدم
utf-8-sigعندما يكون ملف CSV بصيغة UTF-8 مع BOM في البداية. - جرّب
cp1256مع الملفات العربية القديمة المحفوظة من Windows. - لا تقرأ ملفات
.xlsxأو الصور أو PDF كملفات نصية عادية. - استخدم
errors="replace"بحذر عندما تحتاج قراءة مؤقتة للملف. - وحّد ترميز ملفات مشروعك إلى UTF-8 لتقليل المشاكل.
- اكتب ملاحظة في مشروعك عن الترميز المستخدم للملفات.
تدريب عملي
أنشئ ملفًا نصيًا باسم arabic.txt واكتب فيه نصًا عربيًا، ثم احفظه بترميز UTF-8 إن استطعت. بعد ذلك اقرأه باستخدام Python:
with open("arabic.txt", "r", encoding="utf-8") as file:
text = file.read()
print(text)
ثم جرّب قراءة ملف CSV عربي مع معرفة ترميزه أولًا: استخدم utf-8 لملف UTF-8، وutf-8-sig إذا كان UTF-8 مع BOM، وcp1256 إذا كان ملفًا عربيًا قديمًا محفوظًا بهذا الترميز.
حل مختصر للتدريب
encodings = ["utf-8", "utf-8-sig", "cp1256"]
for enc in encodings:
try:
with open("arabic.txt", "r", encoding=enc) as file:
text = file.read()
print("الترميز الصحيح غالبًا:", enc)
print(text)
break
except UnicodeDecodeError:
pass
روابط داخلية مفيدة من بايثون العرب
- سلسلة مشكلة وحل في بايثون
- أساسيات بايثون 29: شرح مكتبة json في Python
- حل خطأ FileNotFoundError في Python عند فتح الملفات
- حل خطأ JSONDecodeError في Python عند قراءة ملفات JSON
مصادر خارجية مفيدة للتوسع
الخلاصة
خطأ UnicodeDecodeError يحدث عندما يحاول Python قراءة ملف بترميز غير مناسب. المشكلة ليست دائمًا في الكود نفسه، بل غالبًا في أن الملف محفوظ بترميز مختلف عن الترميز الذي تستخدمه عند القراءة.
أفضل ممارسة في المشاريع الجديدة هي توحيد الملفات على utf-8 وكتابة encoding="utf-8" بوضوح عند القراءة والكتابة. أما utf-8-sig فيفيد عندما يكون الملف UTF-8 مع BOM، بينما قد تحتاج بعض الملفات العربية القديمة من Windows إلى cp1256 إذا كان هذا هو ترميزها الحقيقي.
الخلاصة العملية: إذا ظهر لك UnicodeDecodeError، لا تغيّر الكود عشوائيًا. اسأل أولًا: ما ترميز الملف؟ ثم جرّب utf-8 أو utf-8-sig أو cp1256 حسب مصدر الملف.
أسئلة شائعة مع إجاباتها
ما معنى UnicodeDecodeError في Python؟
يعني أن Python لم يستطع تحويل محتوى الملف من بايتات إلى نص بسبب استخدام ترميز غير مناسب.
ما سبب UnicodeDecodeError عند قراءة ملف CSV؟
غالبًا يكون ملف CSV محفوظًا بترميز مختلف عن الترميز المستخدم في الكود، مثل قراءة ملف cp1256 باستخدام utf-8.
ما أفضل encoding للملفات العربية في Python؟
في المشاريع الجديدة استخدم utf-8. أما بعض الملفات العربية القديمة من Windows فقد تحتاج إلى cp1256.
متى أستخدم utf-8-sig؟
استخدمه عندما يكون الملف محفوظًا بصيغة UTF-8 مع علامة BOM في البداية. يقوم utf-8-sig بإزالة هذه العلامة عند القراءة، لكنه لا يصلح ملفًا محفوظًا أصلًا بترميز مختلف عن UTF-8.
ماذا يعني invalid start byte في UnicodeDecodeError؟
يعني أن Python وجد بايتًا لا يصلح كبداية لتسلسل صحيح في الترميز المستخدم، مثل UTF-8. غالبًا يكون السبب أن الملف ليس محفوظًا بهذا الترميز، أو أن البيانات ليست نصية أصلًا.
ماذا يعني 'charmap' codec can't decode byte؟
يعني أن Python حاول فك الملف باستخدام ترميز محلي من نوع charmap ولم يستطع تفسير أحد البايتات. إذا كان الملف UTF-8، حدد encoding="utf-8" صراحة؛ وإلا فاستخدم الترميز الحقيقي للملف.
هل errors="ignore" حل جيد؟
ليس دائمًا. قد يخفي المشكلة ويحذف أحرفًا من النص، لذلك الأفضل معرفة الترميز الصحيح أولًا.
هل يمكن قراءة ملف Excel xlsx باستخدام open كنص؟
لا. ملف Excel ليس ملفًا نصيًا عاديًا. استخدم مكتبة مناسبة مثل openpyxl عند التعامل مع ملفات .xlsx.



