التعامل مع الملفات بلغة سي
27 Jun 2020
سأشرح في هذا المقال كيفية التعامل مع الملفات في لغة سي ويتضمن ذلك فتح ملف والقراءة منه أو الكتابة فوقه أو إضافة أسطر له ثم إغلاقه.
فتح وإغلاق ملف وأوضاعهم في لغة سي
هناك دالات عدة في لغة سي للقيام بذلك، وسنستخدم هنا دالتي:
- fopen() لفتح ملف
- fclose() لإغلاقه
حيث يشير الحرف f في البداية إلى الكلمة File أي ملف.
أنماط (أوضاع) فتح الملف مع fopen هي:
-
وضع القراءة
r
اختصارا لـ read حيث يقوم بفتح الملف للقراءة فقط، الملف يجب أن يكون موجودًا. -
وضع الكتابة
w
اختصارًا لـ write ويقوم بإنشاء ملف فارغ جديد للكتابة. إذا كان الملف موجودا فسيقوم بحذف محتوى الملف واعتباره ملف جديد فارغ. -
وضع الإضافة
a
اختصارًا لـ append ويقوم بإضافة محتوى لنهاية ملف موجود. أو يُنشئ ملفا جديدا في حالة عدم وجوده.
لنلقي نظرة الآن على الكود التالي وقد قمت بوضع تعليقات ضمنه بالعربية لفهمه:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
int main (int argc , char ** argv ) {
// argc هو عدد المدخلات عند تشغيل البرنامج من موجه الأوامر
// argv هي مصفوفة المدخلات
// مثلا عند تشغيل أمر من موجه الأوامر وليكن اسم البرنامج a نكتب:
// ./a arg1 arg2
// وبالتالي نكون قد أدخلنا مُدخلين للبرنامج
//mulham.github.io
/* ملف الإدحال */
FILE *f1 ;
/* ملف الإخراج */
FILE *f2 ;
/* local buffer */
char buf[100];
/* counter */
int i;
/* المعطيات أو المدخلات التي يجب أن تعطى عند تشغيل البرنامج هم اثنان
عدا اسم البرنامج نفسه، وإن لم يكن كذلك فسيعطى رسالة خطأ ويتم الخروج من البرنامج
*/
if( argc!= 3)
{
printf(" usage : <name of exe> <inputfiles > <outputfile >!\n");
printf(" Dont forget to create the input file before execution!\n");
exit(-1);
}
/* فتح ملف الإدخال للقراءة */
f1=fopen(argv[1],"rt");
/* في حالة حدوث خطأ بالفتح أعط رسالة خطأ وأنه البرنامج */
if( f1 == NULL )
{
printf(" Error : Can ’t open ’%s’ for read !\n", argv [1]);
exit (-1);
}
/* فتح ملف الإخراج للكتابة حيث سيتم الكتابة فوق الملف الموجود
*/
f2 = fopen(argv[2],"wt");
/* في حالة حدوث خطأ بالفتح أعط رسالة خطأ وأنه البرنامج */
if( f2 == NULL )
{
printf(" Error : can ’t open ’%s’ for write !\n", argv [2]);
exit (-1);
}
/* قراءة ملف الإدخال ضمن 100 بايت وتبديل الأحرف الصغيرة بالكبيرة
* إلى أن يصل لنهاية الملف
*/
while (fgets( buf,100,f1))
{
/* Puffer Zeichen f. Zeichen durchgehen */
for ( i =0; i < strlen ( buf ); i ++)
{
/* falls Kleinbuchstaben */
if(islower( buf[i]))
{
/* dann in den entsp . Grossbuchstaben umwandeln
* dies entspricht der Funktion toupper ()
*/
// يمكن استخدام الدالة toUpper() هنا بدلا من هذه الطريقة
buf[i]+= 'A'-'a';
}
}
fputs (buf,f2); /* Puffer in die Ausgabedatei schreiben */
}
/* إغلاق الملفات وإعطاء رسالة وإنهاء البرنامج */
fclose (f1);
fclose (f2);
printf (" Programm Ende !\n");
return 0;
}
هل لاحظت وجود rt ؟ والسؤال ماهذه الـ t بعد وضعية القراءة r؟
حرف t هنا يُشير للوضع النصي “text mode” ويمكن حذفها! حيث لايوجد فرق بين r و rt أو w و wt وذلك ﻷن الوضع النصي يكون هو الافتراضي.
إذًا هل هناك أوضاع أخرى غير الوضع النصي؟
نعم يوجد b وهو الوضع الثنائي “binary mode”
الفرق بين الوضع النصي والوضع الثنائي في لغة سي
بالنسبة ﻷنظمة لينكس ويونكس بشكل عام فلا يوجد اختلاف بين r و rb. وبالتحديد فإنه عند فتح ملف باستخدام ()fopen فإن المؤشر pointer له يسلك نفس السلوك في كلا الوضعين.
وبالنسبة للويندوز أو بشكل عام للأنظمة التي تستخدم أكثر من محرف (المحرف هو حرف أو رقم أو رمز) لتمثيل “أسطر جديدة” فالملف المفتوح باستخدام ()fopen يتصرف وكأن كل هذه المحارف هي محرف واحد n\
إذا أردت الكتابة أو القراءة من الملفات النصية على أي نظام فاستخدم r و w مع ()fopen (أي بدون تحديد الوضع ثنائي أو نصي) حيث سيضمن ذلك التعامل مع الملف بالشكل الصحيح.
وإذا كنت تفتح ملف ثنائي binary file استخدم rb و wb وبهذا لن تؤذي ترجمة الأسطر الجديدة الخاطئة ملفاتك.