Skip to content

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

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

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

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

C:\>dir

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

C:\>more testfile.txt

هذا اختبار آخر.

تعليقات

  • السطر 7 ينشئ كائن ملف من النوع "Scripting.FileSystemObject" باستخدام الدالة CreateObject("Scripting.FileSystemObject"). يسمح هذا الكائن بالوصول إلى أي ملف على النظام، وليس فقط الملفات النصية.
  • السطر 9 ينشئ كائن "TextStream". يرتبط إنشاء هذا الكائن بإنشاء ملف testfile.txt. لا يتم تحديد هذا الملف بمسار مطلق مثل c:\dir1\dir2\....\testfile.txt بل بمسار نسبي testfile.txt. سيتم إنشاؤه بعد ذلك في الدليل الذي يتم من خلاله تشغيل الأمر لتنفيذ الملف.
  • لا يعرف نظام ملفات Windows مفاهيم مثل الملفات النصية أو الملفات غير النصية. فهو يتعرف فقط على الملفات. ولذلك، فإن الأمر متروك للبرنامج الذي يستخدم هذا الملف لتحديد ما إذا كان سيتعامل معه كملف نصي أم لا.
  • يُنشئ السطر 9 كائنًا، ومن ثم يتم استخدام الأمر SET للتعيين. يتضمن إنشاء كائن ملف نصي إنشاء كائنين:
    • إنشاء Scripting.FileSystemObject (السطر 7)
    • يتبعه إنشاء كائن "TextStream" (ملف نصي) باستخدام طريقة OpenTextFile الخاصة بـ Scripting.FileSystemObject، والتي تقبل عدة معلمات:
      • اسم الملف المراد معالجته (مطلوب)
      • وضع الوصول إلى الملف. وهو عدد صحيح له ثلاث قيم ممكنة:
        • 1: وضع القراءة فقط
        • 2: وضع الكتابة. إذا لم يكن الملف موجودًا بالفعل وإذا كانت المعلمة الثالثة موجودة وقيمتها true، يتم إنشاؤه؛ وإلا، لا يتم إنشاؤه. إذا كان موجودًا بالفعل، يتم الكتابة فوقه.
        • 8: وضع الإلحاق، أي الكتابة في نهاية الملف. إذا لم يكن الملف موجودًا بالفعل وكانت المعلمة الثالثة موجودة ومضبوطة على 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.

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

البرنامج

' creating & filling a text file
Option Explicit
Dim objFichier,MyFile
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim codeErreur

' create a file object
Set objFichier=CreateObject("Scripting.FileSystemObject")

' open a text file that should exist in read-only mode
On Error Resume Next
Set MyFile= objFichier.OpenTextFile("abcd", ForReading)
codeErreur=err.number
On Error GoTo 0
If codeErreur<>0 Then
    ' file does not exist
    wscript.echo "Le fichier [abcd] n'existe pas"
Else
    ' close the text file
    MyFile.Close
End If


' open a text file that must be writable
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
    ' close the text file
    MyFile.Close
End If

' open a text file that should exist as an addition
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
    ' close the text file
    MyFile.Close
End If

' end
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

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

البرنامج

' calculating a taxpayer's tax liability
' the program must be called with three parameters: married children salary
' married: character Y if married, N if unmarried
' children: number of children
' salary: annual salary without cents

' mandatory variable declaration
Option Explicit
Dim erreur

' retrieve arguments and check their validity
Dim marie, enfants, salaire
erreur=getArguments(marie,enfants,salaire)
' mistake?
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit erreur(0)

' retrieve the data needed to calculate taxes
Dim limites, coeffR, coeffN
erreur=getData(limites,coeffR,coeffN)
' mistake?
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit 5

' the result is displayed
wscript.echo "impôt=" & calculerImpot(marie,enfants,salaire,limites,coeffR,coeffN)

' leave without error
wscript.quit 0

' ------------ functions and procedures

' ----------- getArguments
Function getArguments(byref marie, ByRef enfants, ByRef salaire)
    ' must retrieve three values passed as arguments to the main program
    ' an argument is passed to the program without spaces in front and behind it
    ' use regular expressions to check data validity

    ' returns an error array variant with 2 values
    ' error(0): error code, 0 if no error
    ' error(1): error message if error otherwise empty string

    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)"

    ' we check that there are 3 arguments
    Dim nbArguments
    nbArguments=wscript.arguments.count
    If nbArguments<>3 Then
        ' error msg
        getArguments= array(1,syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect")
        ' end
        Exit Function
    End If

    Dim modele, correspondances
    Set modele=new regexp

    ' marital status must be among the characters oOnN
    modele.pattern="^[oOnN]$"
    Set correspondances=modele.execute(wscript.arguments(0))
    If correspondances.count=0 Then
        ' error msg
        getArguments=array(2,syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect")
        ' we leave
        Exit Function
    End If
    ' the value
    If lcase(wscript.arguments(0)) = "o"Then
        marie=true
    Else
        marie=false
    End If

    ' children must be an integer >=0
    modele.pattern="^\d{1,2}$"
    Set correspondances=modele.execute(wscript.arguments(1))
    If correspondances.count=0 Then
        ' error
        getArguments= array(3,syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect")
        ' we leave
        Exit Function
    End If
    ' the value
    enfants=cint(wscript.arguments(1))

    ' salary must be an integer >=0
    modele.pattern="^\d{1,9}$"
    Set correspondances=modele.execute(wscript.arguments(2))
    If correspondances.count=0 Then
        ' error
        getArguments= array(4,syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect")
        ' we leave
        Exit Function
    End If
    ' the value
    salaire=clng(wscript.arguments(2))

    ' finished without error
    getArguments=array(0,"")
End Function

' ----------- getData
Function getData(byref limites, ByRef coeffR, ByRef coeffN)
    ' the data of the three limit tables, coeffR, coeffN are in a text file
    ' called data.txt. Each array occupies a line in the form val1 val2 ... valn
    ' we find, in limit order, coeffR, coeffN

    ' renders a 2-element array error variant to handle possible errors
    ' error(0): 0 if no error, an integer >0 otherwise
    ' error(1): error message if error

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

    ' create a file object
    Set objFichier=CreateObject("Scripting.FileSystemObject")
    ' open the data.txt file in read mode
    On Error Resume Next
    Set MyFile= objFichier.OpenTextFile(dataFileName, ForReading)
    ' mistake?
    codeErreur=err.number
    On Error GoTo 0
    If codeErreur<>0 Then
        ' there has been an error - it is noted
        getData=array(1,"Impossible d'ouvrir le fichier des données [" & dataFileName & "] en lecture")
        ' we're back
        Exit Function
    End If

    ' we now assume that the content is correct and do no verification
    ' read the 3 lines

    ' limits
    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

    ' close the file
    MyFile.close

    ' finished without error
    getData=array(0,"")
End Function

' ----------- getDataFromLine
Sub getDataFromLine(byref ligne, ByRef tableau)
    ' places the numerical values contained in line
    ' these are separated by one or more spaces

    ' initially the table is empty
    tableau=array()
    ' we define a model for the
    Dim modele, correspondances
    Set modele= New RegExP
    With modele
        .pattern="\d+,\d+|\d+"    ' 140.5 or 140
        .global=true              ' all values
    End With

    ' we analyze the line
    Set correspondances=modele.execute(ligne)
    Dim i
    For i=0 To correspondances.count-1
        ' resize the table
        ReDim Preserve tableau(i)
        ' assign a value to the new element
        tableau(i)=cdbl(correspondances(i).value)
    Next

    'end
End Sub




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

    ' the number of shares is calculated
    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

    ' we calculate the family quotient and taxable income
    Dim revenu, qf
    revenu=0.72*salaire
    qf=revenu/nbParts

    ' tax calculation
    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، بالإضافة إلى المصفوفات الثلاثة limit و coeffR و coeffN، نتيجة تشير إلى ما إذا كان قد حدث خطأ أم لا. هذه النتيجة عبارة عن مصفوفة Variant مكونة من عنصرين. العنصر الأول هو رمز الخطأ (0 في حالة عدم وجود خطأ)، والثاني هو رسالة الخطأ في حالة حدوث خطأ.
  • لا تتحقق الدالة getData من صحة القيم الموجودة في ملف data.txt. في سيناريو واقعي، يجب أن تقوم بذلك.