قراءة ملف سطرًا بسطر في Go: من المبتدئ إلى المحترف في 2025
\n\nهل تساءلت يومًا عن كيفية قراءة ملفات السجلات الضخمة أو معالجة بيانات CSV بكفاءة في Go؟ إذا كان الأمر كذلك، فأنت في المكان الصحيح. موضوع قراءة ملف سطرًا بسطر هو أحد أكثر المواضيع شيوعًا على Stack Overflow، وهذا ليس من قبيل الصدفة. تمنحنا Go أدوات قوية، لكن اختيار النهج الصحيح قد يكون صعبًا أحيانًا.
\n\nفي هذه المقالة، لن نعرض فقط كيفية قراءة الأسطر من ملف. بل سنحلل أفضل الممارسات لعام 2025: من bufio.Scanner السريع إلى الحلول المخزنة مؤقتًا المخصصة. ستتعلم كيفية تجنب المخاطر (مثل الأسطر الأطول من 64 كيلوبايت)، ومعالجة الأخطاء بشكل صحيح، وتسريع العمل مع البيانات الضخمة.
هل أنت مستعد؟ هيا بنا!
\n\nلماذا قراءة الأسطر ليست مجرد "أخذ وقراءة"؟
\n\nفي Go، هناك عدة طرق لقراءة الملفات، وكل منها لمهمة محددة. البعض يستخدم ioutil.ReadFile (بالمناسبة، هو deprecated منذ Go 1.16)، والبعض الآخر يستخدم os.File مع مخزن مؤقت. ولكن لمعالجة الأسطر سطرًا بسطر، الملك هو bufio.Scanner.
لماذا؟ لأنه:
\n- \n
- فعال من حيث الذاكرة - لا يقوم بتحميل الملف بأكمله في RAM \n
- سهل الاستخدام - أقل كود ممكن \n
- قادر على معالجة الأخطاء - يتحقق من كل خطوة \n
لكن هناك فارق بسيط: المخزن المؤقت الافتراضي لـ Scanner هو 64 كيلوبايت. إذا كان السطر الخاص بك أطول، فستحصل على خطأ. في مثل هذه الحالات، هناك حاجة إلى نهج أخرى.
\n\nمثال أساسي: bufio.Scanner
\n\nلنبدأ بالطريقة الأكثر شيوعًا. إليك كود عمل بسيط:
\n\npackage 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
هذا الكود مثالي لـ 90% من المهام: ملفات التكوين، السجلات، ملفات CSV الصغيرة.
\n\nمشكلة الأسطر الطويلة: زيادة المخزن المؤقت
\n\nتخيل: أنت تقرأ ملفًا بأسطر JSON بحجم 100 كيلوبايت. سيتعطل Scanner مع خطأ bufio.Scanner: token too long. الحل هو زيادة المخزن المؤقت:
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 ليس عالميًا. إليك حالتان يجب فيهما التفكير في نهج آخر:
1. الملفات الضخمة (غيغابايت)
\nإذا كان الملف أكبر من الذاكرة المتاحة (وهو أمر نادر ولكنه يحدث)، فإن Scanner لا يزال جيدًا. ولكن إذا كنت بحاجة إلى قراءة بيانات ثنائية أو معالجة أسطر بمحددات مخصصة، فمن الأفضل استخدام bufio.Reader:
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\n2. المعالجة بدون تحميل في الذاكرة
\nأحيانًا تحتاج فقط إلى حساب الأسطر أو العثور على نمط. لهذا، سيكون bufio.Scanner مناسبًا