قراءة ملف سطرًا بسطر في Go: أفضل الممارسات لعام 2025

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

قراءة ملف سطرًا بسطر في Go: من المبتدئ إلى المحترف في 2025

\n\n

هل تساءلت يومًا عن كيفية قراءة ملفات السجلات الضخمة أو معالجة بيانات CSV بكفاءة في Go؟ إذا كان الأمر كذلك، فأنت في المكان الصحيح. موضوع قراءة ملف سطرًا بسطر هو أحد أكثر المواضيع شيوعًا على Stack Overflow، وهذا ليس من قبيل الصدفة. تمنحنا Go أدوات قوية، لكن اختيار النهج الصحيح قد يكون صعبًا أحيانًا.

\n\n

في هذه المقالة، لن نعرض فقط كيفية قراءة الأسطر من ملف. بل سنحلل أفضل الممارسات لعام 2025: من bufio.Scanner السريع إلى الحلول المخزنة مؤقتًا المخصصة. ستتعلم كيفية تجنب المخاطر (مثل الأسطر الأطول من 64 كيلوبايت)، ومعالجة الأخطاء بشكل صحيح، وتسريع العمل مع البيانات الضخمة.

\n\n

هل أنت مستعد؟ هيا بنا!

\n\n

لماذا قراءة الأسطر ليست مجرد "أخذ وقراءة"؟

\n\n

في Go، هناك عدة طرق لقراءة الملفات، وكل منها لمهمة محددة. البعض يستخدم ioutil.ReadFile (بالمناسبة، هو deprecated منذ Go 1.16)، والبعض الآخر يستخدم os.File مع مخزن مؤقت. ولكن لمعالجة الأسطر سطرًا بسطر، الملك هو bufio.Scanner.

\n\n

لماذا؟ لأنه:

\n
    \n
  • فعال من حيث الذاكرة - لا يقوم بتحميل الملف بأكمله في RAM
  • \n
  • سهل الاستخدام - أقل كود ممكن
  • \n
  • قادر على معالجة الأخطاء - يتحقق من كل خطوة
  • \n
\n\n

لكن هناك فارق بسيط: المخزن المؤقت الافتراضي لـ Scanner هو 64 كيلوبايت. إذا كان السطر الخاص بك أطول، فستحصل على خطأ. في مثل هذه الحالات، هناك حاجة إلى نهج أخرى.

\n\n

مثال أساسي: bufio.Scanner

\n\n

لنبدأ بالطريقة الأكثر شيوعًا. إليك كود عمل بسيط:

\n\n
package main\n\nimport (\n    "bufio"\n    "fmt"\n    "log"\n    "os"\n)\n\nfunc main() {\n    file, err := os.Open("data.txt")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer file.Close()\n\n    scanner := bufio.NewScanner(file)\n    for scanner.Scan() {\n        line := scanner.Text()\n        fmt.Println(line)\n    }\n\n    if err := scanner.Err(); err != nil {\n        log.Fatal(err)\n    }\n}\n
\n\n

ما المهم هنا؟

\n
    \n
  • defer file.Close() - نغلق الملف حتى في حالة الذعر (panic)
  • \n
  • scanner.Text() - يعيد السطر بدون رمز السطر الجديد (\\n)
  • \n
  • scanner.Err() - نتحقق من عدم وجود أخطاء أثناء القراءة
  • \n
\n\n

هذا الكود مثالي لـ 90% من المهام: ملفات التكوين، السجلات، ملفات CSV الصغيرة.

\n\n

مشكلة الأسطر الطويلة: زيادة المخزن المؤقت

\n\n

تخيل: أنت تقرأ ملفًا بأسطر JSON بحجم 100 كيلوبايت. سيتعطل Scanner مع خطأ bufio.Scanner: token too long. الحل هو زيادة المخزن المؤقت:

\n\n
scanner := bufio.NewScanner(file)\nbuf := make([]byte, 0, 1024*1024) // 1 ميجابايت\nscanner.Buffer(buf, 10*1024*1024) // الحد الأقصى 10 ميجابايت لكل سطر\n\nfor scanner.Scan() {\n    // ... معالجة\n}\n
\n\n

هام: المعامل الثاني هو الحد الأقصى لحجم السطر. إذا كان السطر أكبر، فسيحدث خطأ مرة أخرى. اختر بهامش أمان، ولكن ليس ضخمًا جدًا - الذاكرة ليست مطاطية.

\n\n

عندما لا يكون Scanner مناسبًا: البدائل

\n\n

على الرغم من شعبيته، فإن bufio.Scanner ليس عالميًا. إليك حالتان يجب فيهما التفكير في نهج آخر:

\n\n

1. الملفات الضخمة (غيغابايت)

\n

إذا كان الملف أكبر من الذاكرة المتاحة (وهو أمر نادر ولكنه يحدث)، فإن Scanner لا يزال جيدًا. ولكن إذا كنت بحاجة إلى قراءة بيانات ثنائية أو معالجة أسطر بمحددات مخصصة، فمن الأفضل استخدام bufio.Reader:

\n\n
reader := bufio.NewReader(file)\nfor {\n    line, err := reader.ReadString('\\n')\n    if err != nil {\n        break\n    }\n    // line يحتوي على \\n في النهاية\n    line = strings.TrimRight(line, "\\n")\n    fmt.Println(line)\n}\n
\n\n

الميزة: أنت تتحكم في كل عملية قراءة. العيب: كود أكثر وارتفاع خطر الأخطاء.

\n\n

2. المعالجة بدون تحميل في الذاكرة

\n

أحيانًا تحتاج فقط إلى حساب الأسطر أو العثور على نمط. لهذا، سيكون bufio.Scanner مناسبًا

المدونات

توصيات الكتب