Menu
العربية

قراءة وكتابة ملفات CSV في بايثون بمكتبة csv

تعرّف على كيفية قراءة وكتابة ملفات CSV في بايثون باستخدام وحدة csv و DictReader و DictWriter، مع التعامل مع الترويسات والاقتباس، ومتى تحتاج إلى pandas بدلًا منها.

ملفات CSV أبسط مما تبدو (وأصعب مما تتوقع)

ملف CSV في جوهره ليس سوى نص عادي: أسطر مفصولة بفواصل أسطر، وحقول مفصولة بفواصل. هذه هي الفكرة باختصار. لكن عند التطبيق الفعلي، ستصطدم بسلاسل نصية بين علامات اقتباس تحتوي على فواصل، وحقول بداخلها أسطر جديدة، واختلافات إقليمية في الفاصل (فاصلة أم فاصلة منقوطة)، وملفات محفوظة من Excel تحتوي على BOM في بدايتها… حالات استثنائية كثيرة تجعل كتابة line.split(",") بنفسك خطأً في أغلب الأحيان.

لحسن الحظ، موديول csv المدمج في بايثون يتعامل مع كل هذه التفاصيل نيابةً عنك، ونادرًا ما ستحتاج إلى غيره عند التعامل مع ملفات CSV في python ذات الحجم الصغير أو المتوسط.

قراءة ملف csv بايثون باستخدام csv.reader

الدالة csv.reader تُرجع كل صف على شكل قائمة من السلاسل النصية:

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

بعض التفاصيل اللي مش واضحة من أول وهلة:

  • لازم تمرّر newline="" دائمًا لدالة open. موديول csv بيتكفّل بمعالجة نهايات الأسطر لوحده، ولو أهملت ده هتلاقي صفوف فاضية زيادة لما تشتغل على Windows.
  • كل القيم نصوص. القيمة "42" تفضل نص لحد ما تستدعي عليها int(...) بنفسك. ملفات CSV ما فيهاش أنواع بيانات أصلًا.
  • صف العناوين (header) هو مجرد صف عادي. لو ملفك فيه عناوين، يا إما تتخطى أول صف يدويًا، يا إما تستخدم DictReader بدل كده.

تخطّي صف العناوين

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    headers = next(reader)         # pulls the first row out
    for row in reader:
        print(row)

الدالة next(reader) تحرّك المؤشر خطوة واحدة للأمام وترجع لك هذا الصف.

قراءة ملف CSV كقواميس باستخدام DictReader

يتعامل csv.DictReader مع الصف الأول على أنه رؤوس الأعمدة، ويعطيك كل صف بعده على هيئة قاموس (dict):

import csv

with open("people.csv", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["email"])

هذه الطريقة هي الأنسب في معظم الحالات. أسماء الأعمدة توضح نفسها بنفسها، وإعادة ترتيب الأعمدة في الملف الأصلي لن يكسر الكود عندك.

أما إذا كان الملف بلا رؤوس، فمرِّر الأسماء صراحةً عبر fieldnames=["name", "email", ...].

كتابة ملف CSV باستخدام csv.writer

الدالة csv.writer تحوّل الصفوف (القوائم) إلى أسطر CSV:

import csv

rows = [
    ["name", "age", "city"],
    ["Rosa", 30, "Lisbon"],
    ["Ada", 36, "London"],
]

with open("out.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

writerow(row) تكتب صفًا واحدًا فقط، بينما writerows(rows) تكتب مجموعة صفوف دفعة واحدة. كلتاهما تضع علامات الاقتباس تلقائيًا حول الحقول التي تحتوي على فواصل أو علامات اقتباس أو أسطر جديدة، فلا داعي للقلق بشأن ذلك.

كتابة القواميس باستخدام DictWriter

إذا كانت بياناتك مخزّنة أصلًا على هيئة قواميس، فإن DictWriter يوفّر عليك خطوة تحويلها إلى قوائم:

import csv

people = [
    {"name": "Rosa", "age": 30, "city": "Lisbon"},
    {"name": "Ada", "age": 36, "city": "London"},
]

with open("out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age", "city"])
    writer.writeheader()
    writer.writerows(people)

وسيط fieldnames يتحكّم بعنوان الأعمدة وترتيبها معاً. أي مفتاح في القواميس لا يوجد ضمن fieldnames يُحذف بصمت، أو يمكنك جعله يرمي استثناءً عبر extrasaction="raise".

الفواصل وعلامات الاقتباس المختلفة في ملفات csv

ليست كل ملفات "CSV" تستخدم الفاصلة. كثير من الدول الأوروبية تعتمد ;، والملفات المفصولة بتبويبات تستخدم \t، وبعض الأنظمة تعتمد |. في هذه الحالات مرّر الوسيط delimiter=:

import csv

with open("data.tsv", newline="") as f:
    reader = csv.reader(f, delimiter="\t")
    for row in reader:
        print(row)

بالنسبة للملفات التي تستخدم قواعد اقتباس غير مألوفة، تتيح لك دالة csv.register_dialect(...) ضبط الإعدادات مرة واحدة وإعادة استخدامها لاحقاً. أما في معظم الحالات، فإن الإعدادات الافتراضية مع تحديد delimiter= تفي بالغرض.

الترميز (Encoding)

ملفات CSV هي ملفات نصية في النهاية، ولذلك لها ترميز معيّن. الترميز الافتراضي في زمننا هذا هو UTF-8، لكن الملفات الصادرة من Excel على نظام Windows تأتي أحياناً بترميز cp1252 أو تحتوي على علامة BOM خاصة بـ UTF-8. لذا يُفضَّل أن تكون صريحاً وتحدّد الترميز بنفسك:

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    ...

إذا ظهر لك خطأ UnicodeDecodeError، فهذا يعني أن ترميز الملف مختلف عمّا توقعته. جرّب utf-8-sig (يتعامل مع علامة BOM الخاصة بـ Excel)، أو cp1252، أو latin-1 — هذه هي المشتبه بها الأولى عادةً.

تحويل صفوف ملف CSV إلى أنواع بيانات مناسبة

بما أن كل القيم تصلك على شكل نصوص (strings)، فمسؤولية تحويلها إلى الأنواع الصحيحة تقع على عاتقك:

main.py
Output
Click Run to see the output here.

(الـ StringIO يسمح لنا بتشغيل المثال دون الحاجة لملف فعلي — في الكود الحقيقي ستستخدم open(path).)

إذا كان ملف الـ CSV يحتوي على أنواع بيانات معقّدة (تواريخ، أرقام قد تكون فارغة، قيم true/false مكتوبة بعشر صيغ مختلفة)، فاللجوء إلى مكتبة pandas خيار ممتاز — فهي تتعامل مع معظم هذه الحالات جاهزةً.

متى تستخدم مكتبة pandas لقراءة ملفات CSV؟

الدالة pandas.read_csv(path) تُرجع كائن DataFrame، وهو البنية المناسبة لحظة أن تحتاج إلى:

  • تصفية الصفوف: df[df["active"] == True]
  • التجميع والحساب: df.groupby("city")["age"].mean()
  • الدمج مع جدول آخر
  • كتابة النتائج في ملف جديد بتنسيق بسيط
import pandas as pd

df = pd.read_csv("people.csv")
adults = df[df["age"] >= 18]
adults.to_csv("adults.csv", index=False)

مكتبة Pandas تُعدّ ثقيلة الوزن بالنسبة للقراءات البسيطة والصغيرة، كما أنها تعتمدية ضخمة (تحتاج إلى تثبيتها عبر pip داخل بيئة افتراضية). لكن عندما يتعلق الأمر بأي شيء له طابع البيانات، فهي الأداة التي يلجأ إليها معظم محللي البيانات في بايثون.

التعامل مع الملفات الضخمة جداً عبر البث

الدالة csv.reader كسولة بطبيعتها — فهي تقرأ صفاً واحداً في كل مرة. حافظ على هذا السلوك بالمرور على الصفوف عبر حلقة تكرار (بدلاً من استدعاء list(reader) دفعة واحدة)، وبذلك يبقى استهلاك الذاكرة ثابتاً مهما بلغ حجم الملف:

import csv

with open("huge.csv", newline="") as f:
    reader = csv.DictReader(f)
    error_count = 0
    for row in reader:
        if row["status"] == "error":
            error_count += 1

print(f"Found {error_count} errors.")

وهذا يتعامل مع ملف بحجم 10 جيجابايت بنفس كفاءة ملف بحجم 10 كيلوبايت، طالما أنك لا تجمع الصفوف في قائمة.

بعض العادات المفيدة

  • مرّر دائمًا newline="" إلى open عند قراءة أو كتابة ملفات CSV.
  • استخدم DictReader/DictWriter كلما كان الملف يحتوي على رؤوس أعمدة — فهو أوضح بكثير من استخدام أرقام الفهارس.
  • كن صريحًا بشأن الترميز (encoding)، خاصة مع الملفات القادمة من Excel أو من مصادر بلغات غير الإنجليزية.
  • حوّل الأنواع مباشرة في خطوة القراءة حتى لا يضطر باقي الكود للتعامل مع ذلك لاحقًا.
  • انتقل إلى pandas عندما تريد تحليل البيانات فعليًا، لا مجرد نقلها.

ماذا بعد؟

أصبح بإمكانك الآن قراءة ملفات JSON وCSV. آخر مهارة عملية سنتناولها هي جلب البيانات عبر الشبكة — وهذا موضوع الدرس التالي، حيث سنتعرف على طلبات HTTP باستخدام مكتبة requests.

الأسئلة الشائعة

كيف أقرأ ملف CSV في بايثون؟

استخدم وحدة csv المدمجة. csv.reader يُرجِع كل صف كقائمة من السلاسل النصية، بينما csv.DictReader يعتبر الصف الأول ترويسة ويُرجِع كل صف كقاموس. المهم أن تفتح الملف مع newline='' حتى لا تعبث بايثون بنهايات الأسطر، هكذا:

with open('data.csv', newline='') as f:

كيف أكتب ملف CSV في بايثون؟

استخدم csv.writer مع ملف مفتوح في وضع الكتابة و newline=''. نادِ writer.writerow([...]) لكل صف على حدة، أو writer.writerows([[...], [...]]) لكتابة عدة صفوف دفعة واحدة. وإذا كانت بياناتك على هيئة قواميس، استخدم csv.DictWriter فهو يتولى كتابة الترويسة تلقائيًا.

أيهما أفضل: وحدة csv أم مكتبة pandas؟

استخدم csv للقراءة والكتابة البسيطة والسريعة، وللملفات التي تعالجها صفًا صفًا، أو عندما لا ترغب في إضافة اعتماديات جديدة لمشروعك. أما pandas فاستخدمها إذا كنت بحاجة إلى الفلترة أو التجميع أو الدمج، أو حين يكون الملف كبيرًا بما يكفي لتستفيد من العمليات المتجهة (vectorised). كلتاهما تتعامل مع نفس الملفات، والفرق يكمن في ما ستفعله بالبيانات بعد تحميلها.

لماذا تظهر أسطر فارغة بين الصفوف في ملف CSV على ويندوز؟

السبب أنك فتحت الملف دون تمرير newline=''. وحدة csv تكتب فواصل الأسطر الخاصة بها، وبدون هذا الوسيط تضيف بايثون فواصل إضافية على ويندوز. القاعدة: افتح ملفات CSV دائمًا بـ open(path, newline='') سواء للقراءة أو الكتابة.

تعلّم البرمجة مع Coddy

ابدأ الآن