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 行使用 CreateObject("Scripting.FileSystemObject") 函数创建了一个类型为 "Scripting.FileSystemObject" 的文件对象。此类对象允许访问系统上的任何文件,而不仅仅是文本文件。
  • 第 9 行创建了一个“TextStream”对象。该对象的创建与 testfile.txt 文件的创建相关联。该文件并非通过 c:\dir1\dir2\....\testfile.txt 这样的绝对路径指定,而是通过相对路径 testfile.txt 指定。因此,该文件将创建在执行该文件的命令所在的目录中。
  • Windows 文件系统并不区分文本文件或非文本文件的概念,它仅识别文件本身。因此,是否将该文件视为文本文件,完全取决于使用该文件的程序。
  • 第 9 行创建了一个对象,因此使用了 SET 命令进行赋值。创建文本文件对象涉及创建两个对象:
    • 创建一个 Scripting.FileSystemObject(第 7 行)
    • 随后使用 Scripting.FileSystemObject OpenTextFile 方法创建一个“TextStream”对象(文本文件)该方法接受以下参数:
      • 待处理文件的名称(必填)
      • 文件访问模式。这是一个整数,有三种可能的值:
        • 1:只读模式
        • 2:写入模式。如果文件尚不存在,且第三个参数存在且值为 true,则创建该文件;否则不创建。如果文件已存在,则覆盖原文件。
        • 8:追加模式,即写入文件末尾。如果文件尚不存在,且第三个参数存在并设置为 true,则创建该文件;否则不创建。
  • 第 11 行使用创建的 TextStream 对象的 WriteLine 方法写入一行文本。
  • 第 13 行“关闭”了文件。此后将无法再向该文件写入或从中读取数据。
  • 第 16 行创建了一个新的“TextStream”对象,使用与之前相同的文件,但这次采用“追加”模式。将要写入的行将追加到现有行之后。
  • 第 18 行写入两行新内容,请注意 vbCRLF 常量是文本文件的行尾标记。
  • 第 20 行再次关闭文件
  • 第 23 行以“读取”模式重新打开该文件:我们将读取文件内容。
  • 第 27 行使用 TextStream 对象的 ReadLine 方法读取一行文本。文件首次“打开”时,光标位于文本的第一行。一旦该行被 ReadLine 方法读取,光标便会移至第二行。因此,ReadLine 方法不仅读取当前行,还会自动“移动”到下一行。
  • 要读取所有文本行,必须在循环中反复调用 ReadLine 方法。当 TextStream 对象的 AtEndOfStream 属性被设置为 true 时,该循环(第 26 行)即告结束。这意味着文件中已无更多行可读。

6.2. 错误情况

有两种常见的错误情况:

  • 尝试以读取方式打开不存在的文件
  • 在调用 OpenTextFile 方法时,将第三个参数设置为 false,却尝试打开一个不存在的文件进行写入或追加操作。

以下程序演示了如何检测这些错误:

程序

' 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 函数除了返回三个限值数组 coeffR 和 coeffN 之外,还会返回一个结果,用于指示是否发生错误。该结果是一个包含两个元素的 Variant 数组。第一个元素是错误代码(无错误时为 0),第二个元素是发生错误时的错误消息。
  • getData 函数不会对 data.txt 文件中找到的值进行验证。在实际应用中,它应该进行验证。