Skip to content

6. Pliki tekstowe

Plik tekstowy to plik zawierający wiersze tekstu. Przyjrzyjmy się tworzeniu i wykorzystaniu takich plików na przykładach.

6.1. Tworzenie i wykorzystanie

Program
Wyniki
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.

Komentarze

  • W wierszu 7 tworzony jest obiekt pliku typu „Scripting.FileSystemObject” za pomocą funkcji CreateObject („Scripting.FileSystemObject”). Taki obiekt umożliwia dostęp do dowolnego pliku w systemie, a nie tylko do plików tekstowych.
  • W wierszu 9 tworzony jest obiekt „TextStream”. Utworzenie tego obiektu wiąże się z utworzeniem pliku testfile.txt. Plik ten nie jest określony za pomocą nazwy bezwzględnej w postaci c:\dir1\dir2\....\testfile.txt, lecz za pomocą nazwy względnej testfile.txt. Zostanie on zatem utworzony w katalogu, z którego zostanie uruchomione polecenie wykonania tego pliku.
  • System plików systemu Windows nie rozróżnia pojęć takich jak plik tekstowy czy plik nietekstowy. Rozpoznaje jedynie pliki. To zatem program, który korzysta z tego pliku, musi zdecydować, czy potraktuje go jako plik tekstowy, czy nie.
  • Wiersz 9 tworzy obiekt, z którego pochodzi nazwa set użyta do przypisania. Utworzenie obiektu pliku tekstowego wymaga utworzenia dwóch obiektów:
    • utworzenie obiektu Scripting.FileSystemObject (wiersz 7)
    • a następnie utworzenie obiektu „TextStream” (plik tekstowy) za pomocą metody OpenTextFile obiektu Scripting.FileSystemObject, która przyjmuje kilka parametrów:
      • nazwę pliku, który ma być przetwarzany (obowiązkowe)
      • tryb wykorzystania pliku. Jest to liczba całkowita o trzech możliwych wartościach:
        • 1: korzystanie z pliku w trybie odczytu
        • 2: korzystanie z pliku w trybie zapisu. Jeśli plik jeszcze nie istnieje, a trzeci parametr jest podany i ma wartość true, zostanie utworzony; w przeciwnym razie nie zostanie utworzony. Jeśli plik już istnieje, zostanie nadpisany.
        • 8: dodawanie do pliku, c.a.d. zapis na końcu pliku. Jeśli plik jeszcze nie istnieje, a trzeci parametr jest podany i ma wartość „true”, zostanie utworzony; w przeciwnym razie nie zostanie utworzony.
  • Wiersz 11 zapisuje wiersz tekstu za pomocą metody WriteLine utworzonego obiektu TextStream.
  • Wiersz 13 „zamyka” plik. Nie można już wtedy do niego zapisywać ani z niego odczytywać.
  • W wierszu 16 tworzony jest nowy obiekt „TextStream” w celu obsługi tego samego pliku co poprzednio, ale tym razem w trybie „dodawania”. Nowe wiersze będą zapisywane za istniejącymi wierszami.
  • Wiersz 18 zapisuje dwa nowe wiersze, przy czym stała vbCRLF oznacza znak końca wiersza w plikach tekstowych.
  • Wiersz 20 ponownie zamyka plik
  • Wiersz 23 ponownie otwiera plik w trybie „odczytu”: będziemy odczytywać zawartość pliku.
  • Wiersz 27 odczytuje wiersz tekstu za pomocą metody ReadLine obiektu TextStream. Gdy plik został właśnie „otwarty”, kursor znajduje się na pierwszym wierszu tekstu tego pliku. Gdy wiersz ten zostanie odczytany za pomocą metody ReadLine, kursor zostanie ustawiony na drugim wierszu. W ten sposób metoda Readline nie tylko odczytuje bieżący wiersz, ale następnie automatycznie „przechodzi” do następnego wiersza.
  • Aby przetworzyć wszystkie wiersze tekstu, metodę ReadLine należy stosować wielokrotnie w pętli. Pętla ta (wiersz 26) kończy się, gdy atrybut AtEndOfStream obiektu TextStream przyjmuje wartość true. Oznacza to, że w pliku nie ma już żadnych wierszy do odczytania.

6.2. Przypadki błędów

Występują dwa częste przypadki błędów:

  • otwarcie do odczytu pliku, który nie istnieje
  • Otwarcie pliku w trybie zapisu lub próba dodania pliku, który nie istnieje, przy wartości „false” jako trzecim parametrze w wywołaniu metody OpenTextFile.

Poniższy program pokazuje, jak wykrywać te błędy:

Program
' tworzenie i wypełnianie pliku tekstowego
Option Explicit
Dim objFichier,MyFile
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim codeErreur

' tworzy się obiekt pliku
Set objFichier=CreateObject("Scripting.FileSystemObject")

' otwieranie pliku tekstowego, który musi już istnieć, w trybie odczytu
On Error Resume Next
Set MyFile= objFichier.OpenTextFile("abcd", ForReading)
codeErreur=err.number
On Error GoTo 0
If codeErreur<>0 Then  
    ' plik nie istnieje
    wscript.echo "Le fichier [abcd] n'existe pas"
Else
    ' zamykanie pliku tekstowego  
    MyFile.Close
End If


' otwieramy plik tekstowy, który musi istnieć, w trybie zapisu
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
    ' zamykamy plik tekstowy
    MyFile.Close
End If

' otwierany jest plik tekstowy, który powinien istnieć w trybie dodawania
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
    ' zamykamy plik tekstowy
    MyFile.Close
End If

' koniec
wscript.quit 0
Wyniki
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. Aplikacja IMPOTS z plikiem tekstowym

Wracamy do aplikacji do obliczania podatku, zakładając, że dane niezbędne do obliczenia podatku znajdują się w pliku tekstowym o nazwie 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

Te trzy wiersze zawierają odpowiednio dane z tabel limitów coeffR i coeffN aplikacji. Dzięki modułowej budowie naszej aplikacji zmiany dotyczą głównie procedury getData, odpowiedzialnej za tworzenie tych trzech tabel. Nowy program wygląda następująco:

Program
' obliczenie podatku podatnika
' program należy wywołać z trzema parametrami: stan cywilny, liczba dzieci, wynagrodzenie
' stan cywilny: znak O, jeśli jest żonaty, N, jeśli jest kawalerem
' dzieci: liczba dzieci
' wynagrodzenie: roczne wynagrodzenie bez centów

' obowiązkowa deklaracja zmiennych
Option Explicit
Dim erreur

' argumenty są pobierane po sprawdzeniu ich poprawności
Dim marie, enfants, salaire
erreur=getArguments(marie,enfants,salaire)
' błąd?
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit erreur(0)

' pobieramy dane niezbędne do obliczenia podatku
Dim limites, coeffR, coeffN
erreur=getData(limites,coeffR,coeffN)
' błąd?
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit 5

' wyświetla się wynik
wscript.echo "impôt=" & calculerImpot(marie,enfants,salaire,limites,coeffR,coeffN)

' program kończy działanie bez błędu
wscript.quit 0

' ------------ funkcje i procedury

' ----------- getArguments
Function getArguments(byref marie, ByRef enfants, ByRef salaire)
    ' musi pobrać trzy wartości przekazane jako argumenty do programu głównego
    ' argument jest przekazywany do programu bez spacji przed i po nim
    ' do sprawdzenia poprawności danych zostaną użyte wyrażenia regularne

    ' zwraca tablicę błędów zawierającą 2 wartości
    ' błąd(0): kod błędu, 0, jeśli nie ma błędu
    ' błąd(1): komunikat o błędzie, jeśli wystąpił błąd, w przeciwnym razie pusty ciąg znaków

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

    ' sprawdzamy, czy są 3 argumenty
    Dim nbArguments
    nbArguments=wscript.arguments.count
    If nbArguments<>3 Then
        ' komunikat o błędzie
        getArguments= array(1,syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect")
        ' koniec
        Exit Function
    End If

    Dim modele, correspondances
    Set modele=new regexp

    ' stan cywilny musi należeć do zestawu znaków oOnN
    modele.pattern="^[oOnN]$"
    Set correspondances=modele.execute(wscript.arguments(0))
    If correspondances.count=0 Then
        ' komunikat o błędzie
        getArguments=array(2,syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect")
        ' kończymy
        Exit Function
    End If
    ' pobieramy wartość
    If lcase(wscript.arguments(0)) = "o"Then
        marie=true
    Else
        marie=false
    End If

    ' liczba dzieci musi być liczbą całkowitą >=0
    modele.pattern="^\d{1,2}$"
    Set correspondances=modele.execute(wscript.arguments(1))
    If correspondances.count=0 Then
        ' błąd
        getArguments= array(3,syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect")
        ' kończenie
        Exit Function
    End If
    ' pobieramy wartość
    enfants=cint(wscript.arguments(1))

    ' wynagrodzenie musi być liczbą całkowitą >=0
    modele.pattern="^\d{1,9}$"
    Set correspondances=modele.execute(wscript.arguments(2))
    If correspondances.count=0 Then
        ' błąd
        getArguments= array(4,syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect")
        ' kończymy
        Exit Function
    End If
    ' pobieramy wartość
    salaire=clng(wscript.arguments(2))

    ' zakończono bez błędów
    getArguments=array(0,"")
End Function

' ----------- getData
Function getData(byref limites, ByRef coeffR, ByRef coeffN)
    ' dane z trzech tabel granicznych: coeffR, coeffN znajdują się w pliku tekstowym
    ' o nazwie data.txt. Każda tabela zajmuje jeden wiersz w postaci val1 val2 ... valn
    ' znajdują się w kolejności: coeffR, coeffN

    ' zwraca wariant tablicy błędów zawierający 2 elementy w celu obsługi ewentualnego błędu
    ' błąd(0): 0, jeśli nie ma błędu, w przeciwnym razie liczba całkowita > 0
    ' błąd(1): komunikat o błędzie, jeśli wystąpił błąd

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

    ' tworzy się obiekt pliku
    Set objFichier=CreateObject("Scripting.FileSystemObject")
    ' otwieramy plik data.txt do odczytu
    On Error Resume Next
    Set MyFile= objFichier.OpenTextFile(dataFileName, ForReading)
    ' błąd?
    codeErreur=err.number
    On Error GoTo 0
    If codeErreur<>0 Then
        ' wystąpił błąd – odnotowujemy go
        getData=array(1,"Impossible d'ouvrir le fichier des données [" & dataFileName & "] en lecture")
        ' wprowadzamy dane
        Exit Function
    End If

    ' zakładamy teraz, że zawartość jest poprawna i nie przeprowadzamy żadnej weryfikacji
    ' odczytujemy 3 wiersze

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

    ' zamykamy plik
    MyFile.close

    ' zakończono bez błędów
    getData=array(0,"")
End Function

' ----------- getDataFromLine
Sub getDataFromLine(byref ligne, ByRef tableau)
    ' umieszcza wartości liczbowe zawarte w wierszu w tabeli
    ' wartości te są oddzielone jedną lub kilkoma spacjami

    ' na początku tablica jest pusta
    tableau=array()
    ' określono szablon dla wiersza
    Dim modele, correspondances
    Set modele= New RegExP
    With modele
        .pattern="\d+,\d+|\d+"    ' 140,5 ou 140
        .global=true              ' toutes les valeurs
    End With

    ' analizujemy wiersz
    Set correspondances=modele.execute(ligne)
    Dim i
    For i=0 To correspondances.count-1
        ' zmienia się rozmiar tabeli
        ReDim Preserve tableau(i)
        ' przypisuje się wartość do nowego elementu
        tableau(i)=cdbl(correspondances(i).value)
    Next

    'koniec
End Sub




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

    ' oblicza się liczbę udziałów
    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

    ' oblicza się współczynnik rodzinny i dochód podlegający opodatkowaniu
    Dim revenu, qf
    revenu=0.72*salaire
    qf=revenu/nbParts

    ' oblicza się podatek
    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

Uwagi:

  • w pliku tekstowym data.txt wartości mogą być oddzielone jedną lub kilkoma spacjami, co uniemożliwia użycie funkcji split do pobrania wartości z wiersza. Konieczne było zastosowanie wyrażenia regularnego
  • funkcja getData zwraca, oprócz trzech tablic limitów (coeffR, coeffN), wynik wskazujący, czy wystąpił błąd, czy nie. Wynik ten jest tablicą składającą się z dwóch elementów. Pierwszy element to kod błędu (0, jeśli nie wystąpił błąd), drugi to komunikat o błędzie, jeśli błąd wystąpił.
  • Funkcja getData nie sprawdza poprawności wartości znalezionych w pliku data.txt. W rzeczywistej sytuacji powinna to robić.