Skip to content

6. الملفات النصية

الملف النصي هو ملف يحتوي على أسطر من النص. دعونا نستعرض إنشاء واستخدام هذه الملفات من خلال أمثلة.

6.1. الإنشاء والاستخدام

البرنامج
النتائج
C:\>cscript fic1.vbs

C:\>dir

FIC1     VBS           352  07/01/02   7:07 fic1.vbs
TESTFILE TXT            25  07/01/02   7:07 testfile.txt

C:\>more testfile.txt

Ceci est un autre test.

تعليقات

  • يُنشئ السطر 7 كائن ملف من النوع "Scripting.FileSystemObject" بواسطة الدالة CreateObject("Scripting.FileSystemObject"). يتيح هذا الكائن الوصول إلى أي ملف في النظام، وليس فقط إلى الملفات النصية.
  • السطر 9 ينشئ كائنًا "TextStream". ويرتبط إنشاء هذا الكائن بإنشاء الملف testfile.txt. لا يُشار إلى هذا الملف باسم مطلق من النوع c:\dir1\dir2\....\testfile.txt، بل باسم نسبي هو testfile.txt. وبالتالي، سيتم إنشاؤه في المجلد الذي سيتم منه تشغيل الأمر لتنفيذ الملف.
  • لا يعرف نظام الملفات في نظام ويندوز مفاهيم مثل «ملف نصي» أو «ملف غير نصي». فهو لا يعرف سوى «الملفات» فقط. ولذلك، فإن الأمر متروك للبرنامج الذي يستخدم هذا الملف ليقرر ما إذا كان سيتعامل معه كملف نصي أم لا.
  • يُنشئ السطر 9 كائنًا يُستخدم الأمر set لتعيينه. يتطلب إنشاء كائن ملف نصي إنشاء كائنين:
    • إنشاء كائن Scripting.FileSystemObject (السطر 7)
    • ثم إنشاء كائن «TextStream» (ملف نصي) باستخدام الطريقة OpenTextFile الخاصة بالكائن Scripting.FileSystemObject، والتي تقبل عدة معلمات:
      • اسم الملف المراد معالجته (إلزامي)
      • طريقة استخدام الملف. وهو عدد صحيح له 3 قيم ممكنة:
        • 1: استخدام الملف للقراءة
        • 2: استخدام الملف في وضع الكتابة. إذا لم يكن موجودًا بالفعل، وكان المعلمة الثالثة موجودة وقيمتها true، فسيتم إنشاؤه، وإلا فلن يتم إنشاؤه. إذا كان موجودًا بالفعل، فسيتم استبداله.
        • 8: استخدام الملف في وضع الإضافة، c.a.d. الكتابة في نهاية الملف. إذا لم يكن الملف موجودًا بالفعل، وكان المعلمة الثالثة موجودة وقيمتها «true»، فسيتم إنشاؤه، وإلا فلن يتم إنشاؤه.
  • يكتب السطر 11 سطرًا من النص باستخدام الطريقة WriteLine الخاصة بالكائن TextStream الذي تم إنشاؤه.
  • السطر 13 «يغلق» الملف. وبذلك لا يمكن الكتابة فيه أو قراءته بعد ذلك.
  • السطر 16 ينشئ كائنًا جديدًا «TextStream» لاستخدام نفس الملف كما في السابق، ولكن هذه المرة في وضع «الإضافة». وستُكتب الأسطر الجديدة بعد الأسطر الموجودة.
  • يكتب السطر 18 سطرين جديدين، مع العلم أن الثابت vbCRLF يمثل علامة نهاية السطر في الملفات النصية.
  • السطر 20 يغلق الملف مرة أخرى
  • السطر 23 يعيد فتحه في وضع «القراءة»: سنقوم بقراءة محتوى الملف.
  • يقرأ السطر 27 سطرًا من النص باستخدام الطريقة ReadLine الخاصة بالكائن TextStream. عندما يكون الملف قد «فُتح» للتو، يكون المؤشر موضوعًا على السطر الأول من النص فيه. وعندما يتم قراءة هذا السطر بواسطة الطريقة ReadLine، يتم تحديد الموضع على السطر الثاني. وبالتالي، فإن الطريقة Readline لا تقرأ السطر الحالي فحسب، بل «تنتقل» بعد ذلك تلقائيًا إلى السطر التالي.
  • لتحويل جميع أسطر النص، يجب تطبيق الطريقة ReadLine بشكل متكرر ضمن حلقة. وتنتهي هذه الحلقة (السطر 26) عندما تأخذ السمة AtEndOfStream للكائن TextStream القيمة true. وهذا يعني أنه لم يعد هناك أي أسطر أخرى لقراءتها في الملف.

6.2. حالات الخطأ

هناك حالتان شائعتان للخطأ:

  • فتح ملف غير موجود للقراءة
  • فتح ملف غير موجود للقراءة أو لإضافة بيانات إليه مع تعيين المعلمة الثالثة على «false» عند استدعاء الطريقة OpenTextFile.

يوضح البرنامج التالي كيفية اكتشاف هذه الأخطاء:

البرنامج

' إنشاء ملف نصي وتعبئته
Option Explicit
Dim objFichier,MyFile
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim codeErreur

' يتم إنشاء كائن ملف
Set objFichier=CreateObject("Scripting.FileSystemObject")

' فتح ملف نصي موجود للقراءة
On Error Resume Next
Set MyFile= objFichier.OpenTextFile("abcd", ForReading)
codeErreur=err.number
On Error GoTo 0
If codeErreur<>0 Then
     ' الملف غير موجود
    wscript.echo "Le fichier [abcd] n'existe pas"
Else
     ' إغلاق الملف النصي
    MyFile.Close
End If


' يتم فتح ملف نصي يجب أن يكون موجودًا في وضع الكتابة
On Error Resume Next
Set MyFile= objFichier.OpenTextFile("abcd", ForWriting, False)
codeErreur=err.number
On Error GoTo 0
If codeErreur<>0 Then
    wscript.echo "Le fichier [abcd] n'existe pas"
Else
     ' يتم إغلاق الملف النصي
    MyFile.Close
End If

' يتم فتح ملف نصي يجب أن يكون موجودًا في وضع الإضافة
On Error Resume Next
Set MyFile= objFichier.OpenTextFile("abcd", ForAppending, False)
codeErreur=err.number
On Error GoTo 0
If codeErreur<>0 Then
    wscript.echo "Le fichier [abcd] n'existe pas"
Else
     ' يتم إغلاق الملف النصي
    MyFile.Close
End If

' النهاية
wscript.quit 0

النتائج

C:\>dir

FIC1     VBS           964  07/01/02   7:54 fic1.vbs
TESTFILE TXT             0  07/01/02   8:18 testfile.txt
FIC2     VBS         1 252  07/01/02   8:23 fic2.vbs
3 fichier(s)              2 216 octets
2 répertoire(s)        4 007.11 Mo libre

C:\>cscript fic2.vbs

Le fichier [abcd] n'existe pas
Le fichier [abcd] n'existe pas
Le fichier [abcd] n'existe pas

6.3. تطبيق IMPOTS مع ملف نصي

نستأنف تطبيق حساب الضريبة بافتراض أن البيانات اللازمة لحساب الضريبة موجودة في ملف نصي يسمى data.txt:

12620 13190 15640 24740 31810 39970 48360 55790 92970 127860 151250 172040 195000 0
0 0,05 0,1 0,15 0,2 0,25 0,3 0,35 0,4 0,45 0,5 0,55 0,6 0,65
0 631 1290,5 2072,5 3309,5 4900 6898,5 9316,5 12106 16754,5 23147,5 30710 39312 49062

تحتوي الأسطر الثلاثة على بيانات جداول الحدود coeffR و coeffN الخاصة بالتطبيق، على التوالي. وبفضل تصميم تطبيقنا على أساس الوحدات النمطية، فإن التعديلات تتم بشكل أساسي في الإجراء getData المسؤول عن إنشاء الجداول الثلاثة. وفيما يلي البرنامج الجديد:

البرنامج

' حساب ضريبة أحد دافعي الضرائب
' يجب استدعاء البرنامج بثلاثة معلمات: متزوج، أطفال، راتب
' متزوج: الحرف O إذا كان متزوجًا، وN إذا كان غير متزوج
' الأطفال: عدد الأطفال
' الراتب: الراتب السنوي بدون السنتات

' الإعلان الإلزامي عن المتغيرات
Option Explicit
Dim erreur

' يتم استرداد الوسيطات بالتحقق من صحتها
Dim marie, enfants, salaire
erreur=getArguments(marie,enfants,salaire)
' خطأ؟
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit erreur(0)

' يتم استرداد البيانات اللازمة لحساب الضريبة
Dim limites, coeffR, coeffN
erreur=getData(limites,coeffR,coeffN)
' خطأ؟
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit 5

' يتم عرض النتيجة
wscript.echo "impôt=" & calculerImpot(marie,enfants,salaire,limites,coeffR,coeffN)

' الخروج دون أخطاء
wscript.quit 0

' ------------ الوظائف والإجراءات

' ----------- getArguments
Function getArguments(byref marie, ByRef enfants, ByRef salaire)
     ' يجب أن يسترد ثلاث قيم تم تمريرها كمعلمات إلى البرنامج الرئيسي
     ' يتم تمرير الحجة إلى البرنامج دون مسافات أمامها أو خلفها
     ' سيتم استخدام التعبيرات النمطية للتحقق من صحة البيانات

     ' تُرجع متغيرًا من نوع مصفوفة الأخطاء يحتوي على قيمتين
     ' خطأ(0): رمز الخطأ، 0 في حالة عدم وجود خطأ
     ' خطأ(1): رسالة الخطأ في حالة وجود خطأ، وإلا فإن السلسلة فارغة

    Dim syntaxe
    syntaxe= _
    "Syntaxe : pg marié enfants salaire" & vbCRLF & _
    "marié : caractère O si marié, N si non marié" & vbCRLF & _
    "enfants : nombre d'enfants (entier >=0)" & vbCRLF & _
    "salaire : salaire annuel sans les centimes (entier >=0)"

     ' يتم التحقق من وجود 3 معلمات
    Dim nbArguments
    nbArguments=wscript.arguments.count
    If nbArguments<>3 Then
         ' رسالة خطأ
        getArguments= array(1,syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect")
         ' النهاية
        Exit Function
    End If

    Dim modele, correspondances
    Set modele=new regexp

     ' يجب أن يكون الحالة الاجتماعية من بين الأحرف oOnN
    modele.pattern="^[oOnN]$"
    Set correspondances=modele.execute(wscript.arguments(0))
    If correspondances.count=0 Then
         ' رسالة خطأ
        getArguments=array(2,syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect")
         ' الخروج
        Exit Function
    End If
     ' استرداد القيمة
    If lcase(wscript.arguments(0)) = "o"Then
        marie=true
    Else
        marie=false
    End If

     ' يجب أن تكون «الأطفال» عددًا صحيحًا >=0
    modele.pattern="^\d{1,2}$"
    Set correspondances=modele.execute(wscript.arguments(1))
    If correspondances.count=0 Then
         ' خطأ
        getArguments= array(3,syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect")
         ' الخروج
        Exit Function
    End If
     ' يتم استرداد القيمة
    enfants=cint(wscript.arguments(1))

     ' يجب أن يكون الراتب عددًا صحيحًا >=0
    modele.pattern="^\d{1,9}$"
    Set correspondances=modele.execute(wscript.arguments(2))
    If correspondances.count=0 Then
         ' خطأ
        getArguments= array(4,syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect")
         ' الخروج
        Exit Function
    End If
     ' يتم استرداد القيمة
    salaire=clng(wscript.arguments(2))

     ' انتهى دون أخطاء
    getArguments=array(0,"")
End Function

' ----------- getData
Function getData(byref limites, ByRef coeffR, ByRef coeffN)
     ' بيانات الجداول الثلاثة الحدية، coeffR، coeffN موجودة في ملف نصي
     ' يسمى data.txt. ويحتل كل جدول سطرًا واحدًا بالصيغة val1 val2 ... valn
     ' نجد بالترتيب القيم الحدية: coeffR، coeffN

     ' يعرض متغيرًا لجدول الأخطاء المكون من عنصرين لمعالجة أي خطأ محتمل
     ' خطأ(0): 0 في حالة عدم وجود خطأ، أو عدد صحيح >0 في حالة وجود خطأ
    ' الخطأ(1): رسالة الخطأ في حالة وجود خطأ

    Dim objFichier,MyFile,codeErreur
    Const ForReading = 1, dataFileName="data.txt"

     ' يتم إنشاء كائن ملف
    Set objFichier=CreateObject("Scripting.FileSystemObject")
     ' يتم فتح الملف data.txt للقراءة
    On Error Resume Next
    Set MyFile= objFichier.OpenTextFile(dataFileName, ForReading)
     ' خطأ؟
    codeErreur=err.number
    On Error GoTo 0
    If codeErreur<>0 Then
         ' حدث خطأ - يتم تسجيله
        getData=array(1,"Impossible d'ouvrir le fichier des données [" & dataFileName & "] en lecture")
         ' يتم الإدخال
        Exit Function
    End If

     ' نفترض الآن أن المحتوى صحيح ولا نقوم بأي تحقق
     ' نقرأ الأسطر الثلاثة

     ' الحدود
    Dim ligne, i
    ligne=MyFile.ReadLine
    getDataFromLine ligne,limites

     ' coeffR
    ligne=MyFile.ReadLine
    getDataFromLine ligne,coeffR


     ' coeffN
    ligne=MyFile.ReadLine
    coeffN=split(ligne," ")
    getDataFromLine ligne,coeffN

     ' يتم إغلاق الملف
    MyFile.close

     ' انتهى الأمر دون أخطاء
    getData=array(0,"")
End Function

' ----------- getDataFromLine
Sub getDataFromLine(byref ligne, ByRef tableau)
     ' يضع القيم العددية الموجودة في السطر في جدول
     ' هذه القيم مفصولة بواحدة أو أكثر من المسافات

     ' في البداية، يكون الجدول فارغًا
    tableau=array()
     ' يتم تعريف نموذج للسطر
    Dim modele, correspondances
    Set modele= New RegExP
    With modele
        .pattern="\d+,\d+|\d+"    ' 140,5 ou 140
        .global=true              ' toutes les valeurs
    End With

     ' يتم تحليل السطر
    Set correspondances=modele.execute(ligne)
    Dim i
    For i=0 To correspondances.count-1
         ' يتم تغيير حجم الجدول
        ReDim Preserve tableau(i)
         ' يتم تعيين قيمة للعنصر الجديد
        tableau(i)=cdbl(correspondances(i).value)
    Next

     'النهاية
End Sub




' ----------- calculerImpot
Function calculerImpot(byval marie,ByVal enfants,ByVal salaire, ByRef limites, ByRef coeffR, ByRef coeffN)

     ' يتم حساب عدد الحصص
    Dim nbParts
    If marie=true Then
        nbParts=(enfants/2)+2
    Else
        nbParts=(enfants/2)+1
    End If
    If enfants>=3 Then nbParts=nbParts+0.5

     ' يتم حساب الحصة العائلية والدخل الخاضع للضريبة
    Dim revenu, qf
    revenu=0.72*salaire
    qf=revenu/nbParts

     ' يتم حساب الضريبة
    Dim i, impot
    i=0
    Do While i<ubound(limites) And qf>limites(i)
        i=i+1
    Loop
    calculerImpot=int(revenu*coeffr(i)-nbParts*coeffn(i))
End Function

تعليقات:

  • في الملف النصي data.txt، قد تكون القيم مفصولة بمسافة واحدة أو أكثر، مما يجعل من المستحيل استخدام الدالة split لاستخراج قيم السطر. لذا كان لا بد من استخدام تعبير منتظم
  • تُرجع الدالة getData، بالإضافة إلى الجداول الثلاثة المحددة، coeffR و coeffN، نتيجة تشير إلى ما إذا كان هناك خطأ أم لا. هذه النتيجة عبارة عن متغير صفيفي مكون من عنصرين. العنصر الأول هو رمز الخطأ (0 في حالة عدم وجود خطأ)، والثاني هو رسالة الخطأ في حالة حدوث خطأ.
  • لا تختبر الدالة getData صحة القيم الموجودة في الملف data.txt. في الحالة الفعلية، ينبغي أن تقوم بذلك.