IX.
Zbiory danych
Aplikacje utworzone w poprzednich ćwiczeniach traktowały użytkownika jako źródło danych. Uj-
mując zagadnienie dokładniej, danymi były ciągi znaków odczytywane przez aplikację z klawiatury
konsoli. Wyniki wyprowadzane były na monitor konsoli. W obu przypadkach dane i wyniki miały po -
stać tekstu. Klawiatura występuje zatem jako źródło danych, a monitor jako zbiór wyników.
W rzeczywistości zbiory utworzone przez ludzi, a zawierające informacje, są traktowane jako
zbiory danych, które po przetworzeniu w określony sposób stają się wynikami. Zachowane w trwałej
postaci mogą być zbiorami danych dla kolejnych procesów przetwarzania.
Aby wyniki wyprowadzone na ekran stały się trwałym zbiorem danych aplikacja musi wykorzy-
stać odpowiednią metodę w celu ich zachowania. W przeciwnym przypadku użytkownik musiałby
każdorazowo uruchamiać aplikację generującą wyniki, aby móc je wykorzystać w innym procesie.
Język Visual Basic 2010 pozwala tworzyć zbiory danych, które przechowywane są na różnego
rodzaju nośnikach informacji. Dane mogą być następnie odczytane ze zbioru i przetworzone, a ope -
rację taką można wykonać wielokrotnie.
Tak, jak każda informacja – kod źródłowy projektu, ikona, grafika wektorowa, audycja dźwięko-
wa, dokument tekstowy – dane przechowywane w zbiorze na nośniku, to ciągi liczb. O tym, co przed-
stawiają liczby przechowywane w pliku, zadecyduje sposób ich interpretacji. Wiele aplikacji, przy
podjętej przez użytkownika próbie otwarcia pliku, dokonuje sprawdzenia, czy otwierany plik zawiera
dane, które przez aplikację mogą być interpretowane. Przykładowo, próba otwarcia w edytorze tek-
stowym pliku przechowującego obrazy w formacie JPEG skutkować będzie (w najlepszym przypad-
ku) prośbą do użytkownika o wskazanie właściwej strony kodowej. Natomiast przeglądarka interneto-
wa wyświetli obraz zapisany w pliku.
Visual Basic 2010 realizuje dostęp do plików na trzy sposoby:
sekwencyjny (ang. sequential),
swobodny (random),
binarny (binary).
Dostęp sekwencyjny stosuje się do przetwarzania plików zawierających informacje w postaci
tekstowej. Przetwarzanie plików tekstowych stanowi treść następnego punktu.
IX.1.
Pliki tekstowe
Pliki tekstowe zawierają ciągi znaków reprezentujących litery, cyfry oraz inne dostępne znaki,
a także znaki sterujące takie, jak np. znaki końca wiersza. W takim kontekście plik tekstowy przypo -
mina konsolę z jej urządzeniem wejściowym (np. klawiaturą) i wyjściowym (np. monitorem). Każdy,
kto korzystał z edytora plików tekstowych, ma świadomość, że plik taki można dowolnie edytować.
Jednak zapis danych do takiego pliku, lub odczyt z pliku tekstowego podlega ograniczeniom dostępu
sekwencyjnego. Oznacza to, że zapis informacji może być realizowany jedynie w pozycji końcowej,
która przemieszcza się wraz z ilością zapisanych danych. Odczyt może być realizowany tylko od po-
czątku pliku. Po odczytaniu pewnej ilości informacji punkt odczytu przesuwa się i odczytane dane nie
mogą być odczytane ponownie. Należy przez to rozumieć, że aby odczytać pewną informację zawar-
tą w określonym miejscu pliku przetwarzanego sekwencyjnie trzeba odczytać wszystkie informacje
poprzedzające i dopiero wtedy pobrać informację potrzebną.
Problemem zasadniczym jest utworzenie zbioru z danymi. Sekwencja działań w tym zakresie
jest następująca:
utworzenie pliku i otwarcie go w celu wyprowadzenia do niego informacji,
wyprowadzenie do pliku informacji,
zamknięcie pliku.
Pierwsze działanie realizowane jest w Visual Basic 2010 poprzez procedurę FileOpen, która
zdefiniowana jest w module FileSystem przestrzeni nazw Microsoft.VisualBasic. Moduł FileSystem
zawiera metody przydatne przy operacjach na systemie plików. Chwilowo pominiemy działanie pole-
gające na wyprowadzaniu informacji do otwartego pliku. Natomiast zamknięcie pliku wykonuje się
używając procedury FileClose zdefiniowanej również w module FileSystem. Każdy otwarty plik po-
winien zostać zamknięty. Ponadto przed zmianą kierunku – zapis
↔
odczyt – konieczne jest za-
mknięcie pliku.
Procedura FileOpen posiada sześć parametrów, z których ostatnie trzy są opcjonalne. Pierw-
szy z wymaganych parametrów oznacza numer przydzielony przez aplikację otwieranemu plikowi
i jest typu Integer. Drugi, typu String, to nazwa otwieranego pliku, może to być dowolne wyrażenie,
którego wynikiem jest łańcuch tekstowy przedstawiający ścieżkę do pliku. Może zawierać literę napę-
du oraz nazwy katalogów. Musi zawierać nazwę pliku.
Trzeci parametr, typu OpenMode, określa tryb w jakim plik jest otwierany. Enumeracja OpenMo-
de zawiera pięć stałych:
Input o wartości 1,
Output – 2,
Random – 4,
Apend – 8,
Binary – 32.
Procedura FileClose pozwala na zamknięcie pojedynczego pliku, o numerze przydzielonym
przez procedurę FileOpen, wybranych plików, lub wszystkich otwartych plików. Najprostszym przy-
padkiem jest ostatni. Aby zamknąć wszystkie otwarte pliki należy wywołać procedurę bez parame-
trów. Aby zamknąć plik o określonym numerze, należy podać jego numer jako parametr. W końcu,
aby zamknąć pliki o wybranych numerach, należy jako parametr podać tablicę o komórkach typu In -
teger zawierających numery plików przeznaczonych do zamknięcia. Kolejne ćwiczenie polegać bę-
dzie na utworzeniu pliku tekstowego w katalogu bin\Debug projektu.
Ćwiczenie 109
Utworzyć w katalogu bin\Debug projektu plik tekstowy.
1. Utwórz projekt aplikacji konsolowej.
2. Zaprogramuj w procedurze Main utworzenie i otwarcie pliku Test.txt, w tym celu użyj pro-
cedury FileOpen z parametrami:
◦
1 – numer przydzielany otwieranemu plikowi,
◦
"Test.txt" – nazwa tworzonego pliku, pominięcie litery napędu i nazw katalogów ozna-
cza, że plik ma zostać utworzony w katalogu aplikacji, która go tworzy, zatem plik po-
wstanie w katalogu bin\Debug projektu,
◦
OpenMode.Output – stała określająca kierunek przemieszczania danych; Output
oznacza wyprowadzanie danych z aplikacji do pliku, Input – kierunek odwrotny.
Przykład.
FileOpen(1, "Test.txt", OpenMode.Output)
3. Zaprogramuj zamknięcie pliku o numerze 1, w tym celu użyj procedury FileClose, poda-
jąc jako parametr numer pliku przydzielony przez procedurę FileOpen.
Przykład.
FileClose(1)
4. Uruchom aplikację i sprawdź po jej zakończeniu, czy w katalogu bin\Debug pojawił się
plik tekstowy.
Utworzony plik jest pusty. Plik posłuży do wykazania, że procedura FileOpen, której trzeci pa-
rametr ma wartość OpenMode.Output, tworzy plik. Oznacza to, że jeśli istnieje plik, o nazwie podanej
jako drugi parametr, to zostanie on zastąpiony nowym o takiej samej nazwie. Zatem, jeśli plik zawie-
rał informacje, to zostaną one utracone. W kolejnym ćwiczeniu w pliku zostaną umieszczone informa-
cje. Zostaną one utracone w wyniku działania aplikacji.
Ćwiczenie 110
Sprawdzić, że tworzony plik zastępuje istniejący plik o określonej nazwie.
1. Wprowadź do pliku Test.txt tekst „Ten tekst zostanie utracony.” używając dowolnego edy-
tora tekstowego (najefektywniej będzie wykorzystać do tego celu edytor tekstowy zinte-
growany ze środowiskiem Visual Studio 2010).
2. Uruchom aplikację utworzoną w ćwiczeniu 100.
3. Sprawdź zawartość pliku Test.txt.
Uwaga. Osoby, które skorzystały z edytora Visual Studio, aby wprowadzić tekst do pliku Test.txt,
po wykonaniu aplikacji, otrzymają komunikat o tym, że plik został zmodyfikowany poza edytorem.
Okno zawiera również pytanie, czy załadować plik ponownie. Należy wybrać przycisk Yes.
Fakt potwierdzony w ćwiczeniu 110. powinien wywołać następującą refleksję – tworzenie pliku
musi być zaprogramowane w taki sposób, aby nie powodowało przypadkowej utraty danych.
Umiemy już utworzyć plik tekstowy. Po wywołaniu procedury FileOpen z parametrami, jak
w ćwiczeniu 109. aplikacja może zapisywać teksty do otwartego pliku Test.txt. Służą do tego nastę-
pujące metody:
Print,
PrintLine,
Write,
WriteLine.
Procedura Print wymaga aby jej pierwszym parametrem była liczba typu
Integer
określająca
numer pliku otwartego przez procedurę FileOpen. Kolejne (opcjonalne) parametry to wyrażenia,
których wartość ma być zapisana w pliku tekstowym. Teksty reprezentujące zapisywane wartości roz-
mieszczane są w ten sposób, że pierwszy znak wyprowadzany jest na kolejnej pozycji tabulatora.
Kolejne ćwiczenie będzie ilustracją wykorzystania procedury Print.
Ćwiczenie 111
Wykorzystać procedurę Print w celu wyprowadzenia do pliku danych użytkownika.
1. Zadeklaruj w części deklaracyjnej modułu zmienne strImię i strNazwisko typu String oraz
zmienną intWiek typu Integer.
2. Zaprogramuj, na początku procedury Main, pobranie od użytkownika imienia, nazwiska
oraz liczby lat i przypisanie ich odpowiednim zmiennym.
3. Utwórz pusty wiersz pomiędzy instrukcjami FileOpen i FileClose i umieść w nim kursor
tekstowy.
4. Zaprogramuj wyprowadzenie do otwartego pliku tekstu „Imię użytkownika to:”, w tym celu
wpisz nazwę procedury Print, a jako parametry podaj:
◦
1 – numer pliku otwartego przez procedurę FileOpen,
◦
"Imię użytkownika to:" – tekst wyprowadzany do pliku.
Przykład.
Print(1, "Imię użytkownika to:")
5. Zaprogramuj wyprowadzenie do pliku wartości zmiennej strImię.
Przykład.
Print(1, strImię)
6. Zaprogramuj wyprowadzenie do pliku wartości zmiennej strNazwisko poprzedzonej tek-
stem „Nazwisko użytkownika to:”, w tym celu użyj wymaganego tekstu jako drugiego pa-
rametru procedury Print, a zmiennej strNazwisko jako trzeciego parametru.
Przykład.
Print(1, "Nazwisko użytkownika to:", strNazwisko)
7. Zaprogramuj wyprowadzenie do pliku wartości zmiennej intWiek poprzedzonej tekstem
„Użytkownik ma lat:”.
8. Uruchom aplikację
9. Otwórz w edytorze środowiska plik Test.txt (menu File, grupa poleceń Open, polecenie
File). Jeśli plik był otwarty, to powtórzy się sytuacja opisana w uwadze poniżej ćwicze-
nia 110.
Zawartość pliku może wyglądać następująco:
Imię użytkownika to:KażdosławNazwisko użytkownika to: OgólnyUżytkownik ma lat: 18
Łatwo zauważyć, że kolejne instrukcje Print wyprowadzają tekst w tym miejscu, w którym za-
kończyło się poprzednie wyprowadzanie. Natomiast wartości kolejnych parametrów procedury Print
wyprowadzane są w odstępie tabulatora. Działanie procedury PrintLine różni się tym, że po za-
kończeniu wyprowadzania ostatniego argumentu, wyprowadzane są znaki końca wiersza. Zostanie
to zilustrowane w kolejnym ćwiczeniu.
Ćwiczenie 112
Sprawdzić działanie instrukcji PrintLine.
1. Dodaj pusty wiersz po ostatniej instrukcji Print.
2. Zaprogramuj wyprowadzenie do pliku pustego wiersza, w tym celu użyj procedury Prin-
tLine podając jedynie numer pliku, do którego wiersz ma zostać wyprowadzony.
Przykład.
PrintLine(1)
3. Skopiuj wszystkie instrukcje Print i wklej ich kopię poniżej instrukcji PrintLine.
4. Zastąp każdą instrukcję Print, we wklejonych wierszach, instrukcją PrintLine.
5. Uruchom aplikację, a po jej zakończeniu sprawdź zawartość pliku Test.txt.
Zawartość pliku może wyglądać następująco:
Imię użytkownika to:KażdosławNazwisko użytkownika to: OgólnyUżytkownik ma lat: 18
Imię użytkownika to:
Każdosław
Nazwisko użytkownika to: Ogólny
Użytkownik ma lat: 18
Dziwić może położenie liczby 18 (przesunięta o jeden znak w prawo w stosunku do słowa
„Ogólny”). Przesunięcie spowodowane jest uwzględnieniem miejsca na znak liczby.
Przed wykonaniem kolejnego ćwiczenia należy połączyć w jedną procedury PrintLine wyprowa-
dzające do pliku tekst „Imię użytkownika to:” oraz wartość zmiennej strImię.
Istnieją dwie funkcje SPC oraz TAB przydatne do ustalania położenia kolejnych tekstów wypro-
wadzanych do pliku. Funkcja SPC generuje tekst składający się ze spacji. Liczba spacji zależna jest
od wartości argumentu funkcji. Funkcja TAB generuje tabulator przenoszący wyprowadzanie tekstu
do kolumny o numerze zależnym od wartości argumentu funkcji, jeśli argument zostanie pominięty, to
tekst przesuwany jest do następnej strefy tabulatora. Kolejne ćwiczenie pokazuje wykorzystanie obu
funkcji.
Ćwiczenie 113
Wykorzystać funkcje SPC oraz TAB do rozłożenia tekstu w pliku.
1. Dodaj, jako drugi parametr procedur PrintLine wywołanie funkcji SPC generującej 5 spa-
cji.
Przykład.
PrintLine(1, SPC(5), "Imię użytkownika to:", strImię)
2. Dodaj jako czwarty parametr wywołanie funkcji TAB generującej tabulator przesuwający
tekst do czterdziestej kolumny.
Przykład.
PrintLine(1, SPC(5), "Imię użytkownika to:", TAB(40), strImię)
3. Uruchom aplikację, a po jej zakończeniu sprawdź zawartość pliku Test.txt.
Zawartość pliku może wyglądać następująco:
Imię użytkownika to:KażdosławNazwisko użytkownika to: OgólnyUżytkownik ma lat: 18
Imię użytkownika to: Każdosław
Nazwisko użytkownika to: Ogólny
Użytkownik ma lat: 18
Należy pamiętać, aby szerokości uzyskiwanych kolumn tekstu były wystarczające do pomiesz-
czenia w nich wyprowadzanych tekstów.
Łańcuchy tekstowe zawarte w wierszach pliku mogą powstawać w wyniku różnych działań apli-
kacji. Przykładowo, treść drugiego wiersza mogła powstać jako efekt instrukcji:
PrintLine(1, " Imię użytkownika to:", TAB(40), strImię)
albo
PrintLine(1, " Imię użytkownika to: Każdosław")
Jeśli zależy nam na tym, aby możliwa była identyfikacja poszczególnych elementów wyprowa-
dzanych do pliku, powinniśmy użyć procedur Write lub WriteLine. Wywołania obu procedur wy-
magają identycznych parametrów jak Print lub PrintLine. Ponieważ różnica pomiędzy działa-
niem procedury Write i WriteLine polega jedynie na wyprowadzaniu przez drugą z nich znaków
końca wiersza, omówione zostanie działanie tylko pierwszej z nich. Wcześniej poczynimy pewne za-
łożenia. Niech wywołanie ma postać:
Write(NumerPliku, strImię, intWiek)
i dodatkowo strImię jest zmienną typu
String
, a intWiek typu
Integer
. Procedura Write wyprowadza
reprezentacje tekstowe parametrów do pliku rozdzielając je przecinkami. Dodatkowo teksty wyprowa-
dzane są w cudzysłowie. Taki tryb działania pozwala w łatwy sposób zinterpretować zawartość pliku
– przecinek oznacza koniec dodanej treści, a jeśli jest ona objęta cudzysłowem, to znaczy, że była
tekstem. Ponieważ znaki końca wiersza jednoznacznie wskazują miejsce zakończenia danych, to po
wyprowadzeniu ostatniego parametru procedura WriteLine nie dodaje przecinka. Kolejne ćwicze-
nie pokazuje działanie procedur Write i WriteLine.
Ćwiczenie 114
Zapoznać się ze sposobem działania procedur Write i WriteLine.
1. Dodaj przed instrukcją FileClose kopię wszystkich wierszy wywołujących procedury Print
(PrintLine) i zamień wszystkie wystąpienia słowa „Print” w kopiach na słowo „Write”.
2. Uruchom aplikację i po jej zakończeniu sprawdź zawartość pliku Test.txt.
Zawartość pliku może być podobna do przedstawionej na rysunku:
Imię użytkownika to:KażdosławNazwisko użytkownika to: OgólnyUżytkownik ma lat: 18
Imię użytkownika to: Każdosław
Nazwisko użytkownika to: Ogólny
Użytkownik ma lat: 18
"Imię użytkownika to:","Każdosław","Nazwisko użytkownika to:","Ogólny","Użytkownik ma
lat:",18,
"Imię użytkownika to:", ,"Każdosław"
"Nazwisko użytkownika to:","Ogólny"
"Użytkownik ma lat:",18
Widać wyraźnie różnicę pomiędzy działaniem procedur Print (PrintLine) i Write
(WriteLine). Każdy tekst objęty jest cudzysłowem. Procedura Write dodaje przecinek po każdym
parametrze, a procedura WriteLine nie dodaje przecinka po ostatnim parametrze.
Umiemy już utworzyć plik tekstowy i zapisać w nim informacje. Mogą być one następnie odczy-
tywane przez inny (lub ten sam) program w celu przetworzenia. Istotne jest przyswojenie sposobu
działania procedur Print i Write. Można oczywiście zastąpić każdą z nich tą drugą, ale będzie to
wymagało dodatkowego nakładu pracy. Generalnie należy się kierować następującą zasadą – jeśli
analizę treści pliku będzie realizować program, to należy korzystać z procedur Write, gdyż ułatwiają
interpretację. W przypadku gdy treść odczytana z pliku będzie interpretowana przez użytkownika,
można posłużyć się procedurami Print.
Przed przystąpieniem do ćwiczeń dotyczących odczytu informacji z pliku tekstowego wykonamy
ćwiczenie przygotowujące dwa pliki przeznaczone do odczytu przez różne procedury.
Ćwiczenie 115
Przygotować dwa pliki przy użyciu procedur Print i Write.
1. Utwórz projekt aplikacji konsolowej.
2. Zadeklaruj w procedurze Main zmienną strTekst typu String.
3. Zaprogramuj:
◦
utworzenie pliku o nazwie PrintTest.txt i otwarcie go w trybie OpenMode.Output,
◦
pętlę For wykonywaną 5 razy, a w niej:
▪
pobranie od użytkownika dowolnego tekstu i przypisanie go zmiennej strTekst,
▪
wyprowadzenie wartości zmiennej strTekst do pliku przy użyciu procedury PrintLi-
ne;
◦
zamknięcie (po zakończeniu pętli) pliku PrintTest.txt.
4. Zadeklaruj zmienną intLiczba typu Integer.
5. Zaprogramuj:
◦
utworzenie pliku o nazwie WriteTest.txt i otwarcie go w trybie OpenMode.Output,
◦
pętlę For wykonywaną 5 razy, a w niej:
▪
przypisanie zmiennej strTekst tekstu „Liczba nr #”, gdzie znak # należy zastąpić
wartością zmiennej sterującej pętlą,
▪
pobranie od użytkownika liczby całkowitej i przypisanie jej zmiennej intLiczba,
▪
wyprowadzenie wartości zmiennych strTekst i intLiczba do pliku przy użyciu proce-
dury WriteLine;
◦
zamknięcie (po zakończeniu pętli) pliku WriteTest.txt.
6. Uruchom program, a po jego zakończeniu sprawdź treść obu plików.
Po wykonaniu aplikacji, której przykładowe działanie przedstawiono na rysunku:
pliki powinny zawierać informacje w postaci przedstawionej na kolejnych dwóch rysunkach.
Plik PrintTest.txt:
Dowolny text
Ala ma kota.
Ola ma psa.
Pies Oli nie lubi kota Ali.
Ala lubi Olę.
Plik WriteTest.txt:
"Liczba nr 1",1
"Liczba nr 2",3
"Liczba nr 3",5
"Liczba nr 4",7
"Liczba nr 5",9
Do odczytu informacji z pliku tekstowego służą metody:
InputString,
LineInput,
Input.
Aby możliwy był odczyt z pliku konieczne jest otwarcie go w trybie do odczytu – OpenMode.In-
put. Zostało to już wcześniej zasygnalizowane, ale powtórzmy – aby zmienić tryb, w którym plik zo-
stał otwarty, należy go zamknąć, a następnie otworzyć w żądanym trybie. Instrukcja otwierająca plik
w trybie do odczytu może mieć następującą postać:
FileOpen(intNumerPliku, strNazwaPliku, OpenMode.Intput)
Procedura FileOpen otwierając plik w trybie Input nie tworzy nowego pliku (jak w trybie Out-
put). Pociąga to za sobą konieczność podania nazwy istniejącego pliku. Jeśli plik o podanej nazwie
nie istnieje wystąpi błąd. Kolejny raz istotne wydaje się sprawdzenie przed użyciem procedury
FileOpen faktu istnienia pliku o podanej nazwie.
Rysunek 48: Projekt_115 w działaniu.
Z otwartego w trybie Input pliku można pobierać dane. Po zakończeniu pobierania danych plik
należy zamknąć używając procedury FileClose.
Funkcja InputString posiada dwa parametry. Pierwszy, to numer pliku otwartego w trybie In-
put. Drugi, określa liczbę znaków, które należy odczytać z pliku. Działanie funkcji przedstawia kolejne
ćwiczenie.
Ćwiczenie 116
Wykorzystać funkcję InputString do odczytu z pliku łańcucha znaków o określonej
długości.
1. Utwórz projekt aplikacji konsolowej i zapisz go (File\Save All). Wymuszenie zapisu pro-
jektu ma na celu utworzenie katalogu projektu, do którego będzie można skopiować pliki.
2. Skopiuj do katalogu bin\Debug projektu pliki PrintTest.txt oraz WriteTest.txt utworzone
przez aplikację wykonaną w poprzednim ćwiczeniu.
3. Zaprogramuj:
◦
otwarcie pliku PrintTest.txt w trybie do odczytu,
Przykład.
FileOpen(1, "PrintTest.txt", OpenMode.Input)
◦
wyświetlenie w konsoli pierwszych 15 znaków odczytanych z pliku przez funkcję In-
putString,
Przykład.
Console.WriteLine(InputString(1, 15))
◦
zamknięcie pliku.
4. Uruchom aplikację i przelicz znaki wyświetlone w konsoli.
Przykładowy efekt działania aplikacji przedstawia rysunek:
Łącznie ze spacjami, w konsoli pojawiło się 13 znaków. Brakujące dwa znaki, to znaki sterujące.
Pierwszy z nich (#13) to polecenie powrotu kursora do pierwszej kolumny. Ze względów historycz-
nych znak ten nazywa się „powrót karetki” (ang. carriage return) – karetka, to część maszyny do pi-
sania przenosząca papier pod głowicą drukującą (lub młoteczkami), a w drukarkach z ruchomą głowi-
cą – część przenosząca głowicę. Drugi znak (#10), to polecenie wciągnięcia papieru o linię (ang. line
Rysunek 49: Projekt_116 w działaniu.
feed). Połączenie tych dwóch znaków sterujących jest jednoznaczne z przejściem do początku nowe-
go wiersza. Widać zatem, że liczba wczytanych z pliku znaków rzeczywiście wynosi 15.
Funkcja LineInput, której wynik jest typu
String
, wymaga tylko jednego parametru – numeru
otwartego pliku, z którego ma nastąpić odczyt. Funkcja odczytuje z pliku tekst aż do napotkania zna-
ków końca wiersza (#13#10), co kończy odczyt. Odczytane znaki (bez znaków końca wiersza) zwra-
cane są jako wynik funkcji. Obrazuje to kolejne ćwiczenie.
Ćwiczenie 117
Zapoznać się z działaniem funkcji LineInput.
1. Dodaj pusty wiersz po instrukcji zamykającej plik.
2. Zadeklaruj w dodanym wierszy zmienną strTeksty typu String o wartość początkowej ″″.
3. Zaprogramuj:
◦
otwarcie pliku PrintTest.txt w trybie do odczytu,
◦
pętlę For wykonywaną pięciokrotnie, a w niej odczyt wiersza znaków z otwartego pli-
ku i dołączenie odczytanych znaków do zmiennej strTeksty,
Przykład.
strTeksty &= LineInput(1)
◦
zamknięcie pliku (po zakończeniu pętli).
4. Wyświetlenie wartości zmiennej strTeksty w konsoli.
5. Uruchom aplikację.
Przykładowe działanie aplikacji przedstawia rysunek:
Teksty kolejnych wierszy zapisanych w pliku tworzą jeden wiersz ze względu na działanie funk-
cji InputLine, która zwraca jedynie treść wiersza bez znaków, które go kończą. Znaki te można do-
łączyć do zmiennej strTeksty posługując się stałą vbCrLf zdefiniowaną w module Constants.
Przykład.
strTeksty &= LineInput(1) & vbCrLf
Procedura Input działa odmiennie niż funkcje InputString i LineInput. Posiada ona dwa
parametry. Pierwszy, jak zwykle, oznacza numer pliku otwartego do odczytu. Drugi jest zmienną, któ-
rej zostanie przypisana wartość odczytana z pliku. Procedura interpretuje odczytywane informacje
Rysunek 50: Projekt_116 po modyfikacji.
zgodnie z typem zmiennej, która jest drugim parametrem, w związku z tym jest szczególnie przydat -
na do wprowadzania danych z plików utworzonych przez procedury Write. Działanie procedury In-
put ilustruje kolejne ćwiczenie.
Ćwiczenie 118
Zapoznać się z działaniem procedury Input.
1. Dodaj przed końcem procedury Main pusty wiersz.
2. Zadeklaruj zmienną strTekst typu String o wartości początkowej ″″ i zmienną intLiczba
typu Integer.
3. Zaprogramuj:
◦
otwarcie pliku WriteTest.txt w trybie do odczytu,
◦
pętlę For wykonywaną pięciokrotnie, a w niej:
▪
odczyt z otwartego pliku (wykorzystaj procedurę Input):
•
tekstu i przypisanie go zmiennej strTekst,
•
liczby i przypisanie jej zmiennej intLiczba;
▪
wyświetlenie w konsoli wartości zmiennych strTekst i intLiczba połączonych łańcu-
chem znaków „ to ”;
◦
zamknięcie pliku (po zakończeniu pętli).
4. Uruchom aplikację.
Przykładowy efekt działania aplikacji może być następujący:
Procedura odczytuje dane aż do napotkania przecinka, lub znaków końca wiersza. Odczytany
tekst interpretowanych jest zgodnie z typem zmiennej, której ma być przypisany. Jeśli jest to zmienna
typu liczbowego, to tekst konwertowany jest na liczbę. Należy przykładać szczególną uwagę do fak -
tu, że przecinek jest separatorem danych. Jeśli w pliku zostanie zapisana liczba rzeczywista, a zna -
kiem rozdzielającym część całkowitą od ułamkowej będzie przecinek, to podczas odczytu przez pro-
cedurę Input zostanie odczytana najpierw część przed przecinkiem (jako jedna informacja), a przy
Rysunek 51: Projekt_116 po kolejnej modyfikacji.
drugim odczycie część ułamkowa (jako kolejna informacja). Należy pamiętać, aby liczby rzeczywiste
zapisywane były z kropką dziesiętną, a nie z przecinkiem.
W zestawie ćwiczeń dwukrotnie pojawił się problem istnienia (lub braku) otwieranego pliku.
W pierwszym przypadku chodziło o możliwość przypadkowego zniszczenia danych w trakcie tworze-
nia pliku o takiej samej nazwie jak plik wcześniej utworzony. W drugim przypadku występowała możli -
wość próby otwarcia do odczytu pliku, który nie istnieje. W obu przypadkach pomocna okaże się
funkcja Exists (Istnieje) zdefiniowana w klasie
File
(Plik) przestrzeni nazw System.IO (IO –
Input/Output – Wejście/Wyjście). Z funkcji tej należy korzystać w taki sam sposób jak np. z funkcji
klasy Math.
Przykład.
Dim boolPlikIstnieje as Boolean = System.IO.File.Exists("NazwaPliku.roz")
Funkcja zwraca wartość True jeśli istnieje plik o nazwie podanej jako parametr, lub False jeśli
plik nie istnieje. Przy tym nazwę pliku można poprzedzić literą napędu, lub nazwami katalogów, albo i
jednym i drugim. Jeśli podana jest wyłącznie nazwa pliku, to funkcja sprawdza katalog aplikacji. Ko -
lejne ćwiczenie pokazuje sposób w jaki można wykorzystać funkcję Exists.
Ćwiczenie 119
Zmodyfikować procedurę Main w taki sposób, aby otwieranie plików było „bezpieczne” –
poprzedzane sprawdzeniem istnienia pliku, który ma zostać otwarty.
1. Dodaj na początku procedury Main pusty wiersz.
2. Zadeklaruj zmienną strNazwaPliku typu String o wartości początkowej "PrintTest.txt".
3. Zadeklaruj zmienną boolPlikIstnieje typu Boolean i przypisz jej wynik sprawdzenia, czy
istnieje plik o nazwie przechowywanej w zmiennej strNazwaPliku.
Przykład.
Dim boolPlikIstnieje as Boolean = System.IO.File.Exists(strNazwaPliku)
4. Utwórz konstrukcję warunkową, której instrukcje zostaną wykonane pod warunkiem, że
zmienna boolPlikIstnieje ma wartość True.
Przykład.
If boolPlikIstnieje Then
5. Przenieś do konstrukcji warunkowej wszystkie instrukcje odnoszące się do pliku "Print-
Test.txt".
6. Przypisz, po konstrukcji warunkowej, zmiennej strNazwaPliku wartość "WritTest.txt" (lite-
rę „e” pominięto celowo, aby uzyskać nazwę pliku, który nie istnieje).
7. Przypisz zmiennej boolPlikIstnieje wynik sprawdzenia czy istnieje plik o nazwie przecho-
wywanej w zmiennej strNazwaPliku.
8. Utwórz konstrukcję warunkową, której instrukcje będą wykonane pod warunkiem, że
zmienna boolPlikIstnieje ma wartość True.
9. Przenieś do konstrukcji warunkowej wszystkie instrukcje odnoszące się do pliku "Write-
Test.txt".
10.Uruchom aplikację.
Przykład działania aplikacji przedstawia rysunek:
Widać, że instrukcje zawarte w drugiej konstrukcji warunkowej nie zostały wykonane, gdyż funk-
cja Exists zwróciła wartość False. Konstrukcję warunkową można rozbudować o część
Else
,
w której zaprogramowane będzie informowanie użytkownika, że plik o podanej nazwie nie istnieje.
Modyfikację tą pozostawia się ćwiczącym do samodzielnego wykonania.
Wykonane ćwiczenia pozwalają utworzyć plik, zapisać do niego informacje, a także odczytać je.
Często występuje potrzeba zachowania informacji wcześniejszych, a dopisania nowych. Przykładem
mogą tu być wszelkiego rodzaju „logi”, czyli pliki przechowujące informacje o pewnych wydarzeniach.
Do tego rodzaju pracy potrzebny jest oddzielny (inny niż do tworzenia i zapisu oraz inny niż
do odczytu) tryb otwierania pliku. Plik musi być otwarty w taki sposób, aby możliwy był zapis, ale
miejsce zapisu musi być ustawione w pozycji końcowej pliku. Procedura FileOpen wykonuje takie
zadanie jeśli trzeci parametr ma wartość OpenMode.Append.
Przykład.
FileOpen(NumerPliku, NazwaPliku, OpenMode.Append)
Jeśli nie istnieje plik o nazwie podanej w parametrze NazwaPliku, to zostanie utworzony, a na -
stępnie otwarty do zapisu, podobnie jak w trybie Output. W kolejnym ćwiczeniu wykorzystany zosta -
nie tryb dopisywania informacji do pliku.
Ćwiczenie 120
Wykorzystać możliwe tryby pracy z plikiem o dostępie sekwencyjnym, w tym dokonać
dołączenia nowych danych do pliku.
1. Utwórz projekt aplikacji konsolowej.
2. Zadeklaruj zmienną intLiczba typu Integer.
3. Utwórz pętlę Do z warunkiem While sprawdzanym na końcu pętli. Pętla powinna być wy-
konywana tak długo, jak długo zmienna intLiczba nie jest równa zeru.
Rysunek 52: Zabezpieczenie przed otwieraniem nieistniejącego pliku działa.
4. Zaprogramuj w pętli:
◦
pobranie wartości zmiennej intLiczba od użytkownika,
◦
otwarcie pliku „Liczby.dat” w trybie dopisywania,
Przykład.
FileOpen(1, "Liczby.dat", OpenMode.Append)
◦
wyprowadzenie wartości zmiennej intLiczba do pliku; użyj procedury Write,
◦
zamknięcie pliku.
5. Uruchom aplikację kilka razy, każdorazowo podając po kilka liczb całkowitych.
6. Sprawdź zawartość pliku Liczby.dat.
Umiemy już utworzyć plik, zapisać do niego informacje, otworzyć plik istniejący i odczytać z nie -
go informacje, a także otworzyć plik i dopisać do niego informacje. Plik Liczby.dat może mieć, przy-
kładowo, taką zawartość:
1,3,5,7,9,0,1,3,5,0,25,36,14,69,58,47,0,
Biorąc pod uwagę to, że zero stanowi rodzaj separatora, można powiedzieć, że plik zawiera trzy
ciągi liczb całkowitych. Ciągi mają różną długość, a ich liczba nie jest ograniczona. Przy odczycie da-
nych z pliku łatwo sprawdzić, że ciąg zakończył się – świadczy o tym odczytana w kolejnym kroku
wartość zerowa. Pozostaje jednak pytanie, skąd program ma wiedzieć, że ciąg, który właśnie zakoń-
czył odczytywać, był ostatni. Jest to pytanie o tyle istotne, że kolejny odczyt, gdy w pliku nie ma już
danych zakończy się błędem. Język Visual Basic 2010 posiada funkcję rozwiązującą ten problem.
Jest to funkcja EOF o wyniku typu
Boolean
. Jedynym parametrem funkcji jest numer otwartego pliku.
Przykład.
Dim boolPlikWPozycjiKońcowej As Boolean = EOF(NumerPliku)
Jeśli otwarty plik o numerze NumerPliku znajduje się w pozycji końcowej (ang. End Of File),
to wartością funkcji jest True, w przypadku przeciwnym False. Kolejne ćwiczenie zapoznaje z wyko-
rzystaniem funkcji EOF.
Ćwiczenie 121
Zaprojektować aplikację obliczającą sumy ciągów zawartych w pliku Liczby.dat.
1. Utwórz projekt aplikacji konsolowej i zapisz go.
2. Skopiuj plik Liczby.dat utworzony w ćwiczeniu 120. do katalogu bin\Debug utworzonego
projektu.
3. Zaprogramuj otwarcie do odczytu pliku Liczby.dat.
4. Utwórz pętlę While z warunkiem sprawdzającym czy plik otwarty w poprzednim punkcie
nie jest w pozycji końcowej.
Przykład.
While Not Eof(1)
5. Zadeklaruj w pętli While zmienną intSuma typu Integer o wartości początkowej równej 0
oraz zmienną intLiczba typu Integer.
6. Utwórz pętlę Do z warunkiem While sprawdzanym na końcu pętli. Pętla powinna być wy-
konywana tak długo, jak długo wartość zmiennej intLiczba nie jest równa 0.
7. Zaprogramuj w pętli Do:
◦
odczyt z pliku kolejnej liczby i przypisanie jej do zmiennej intLiczba; użyj procedury In-
put,
◦
zwiększenie wartości zmiennej intSuma o wartość zmiennej intLiczba.
8. Zaprogramuj po zakończeniu pętli Do wyświetlenie w konsoli komunikatu o sumie ciągu.
9. Sprawdź działanie aplikacji.
Efekt działania aplikacji może być podobny do przedstawionego na rysunku:
Treść pliku tekstowego można odczytać w większości aplikacji pozwalających otworzyć i wy-
świetlić zawartość pliku. W związku z tym znaczenie plików tekstowych będzie się utrzymywać,
ze względu na to, że informacje w nich zawarte mogą być odczytane przez człowieka bez potrzeby
ich przetwarzania. Można nawet zaobserwować rosnące znaczenie plików tekstowych zawierających
znaczniki.
Jednak przetwarzanie sekwencyjne niesie ze sobą problemy sygnalizowane już wcześniej.
Przykładowo, nie istnieje taki tryb pracy z plikiem o dostępie sekwencyjnym, który pozwoliłby odczy -
tać wartość inną niż ta, która jest następna do odczytu. Nie można, po odczytaniu kilku wartości, „cof-
nąć się” do wartości już odczytanej – konieczne będzie zamknięcie pliku i ponowne odczytanie
wszystkich wartości poprzedzających pożądaną. Problemy takie nie występują w plikach o dostępie
swobodnym.
IX.2.
Pliki o dostępie swobodnym
Pliki o dostępie swobodnym (ang. Random Access Files) pozwalają na dostęp do informacji za-
wartej w dowolnym miejscu pliku. Nie ma potrzeby zmiany trybu dostępu, gdyż po otwarciu pliku
możliwy jest tak odczyt danych, jak i zapis danych. Jednak występuje ograniczenie innego typu, infor-
Rysunek 53: Projekt_121 w działaniu.
macje zapisywane lub odczytywane muszą mieć ściśle określony rozmiar. Aby uwypuklić zalety try-
bów sekwencyjnego i swobodnego oraz różnice pomiędzy nimi pierwsze ćwiczenie niniejszego punk-
tu dotyczyć będzie pliku o dostępie sekwencyjnym.
Ćwiczenie 122
Zaprojektować aplikację pozwalającą utworzyć plik do przetwarzania w trybie
sekwencyjnym. Plik powinien przechowywać dane osobowe: Imię, Nazwisko i wiek w
latach.
1. Utwórz projekt aplikacji konsolowej.
2. Dodaj do projektu nowy moduł o nazwie Osoba.
3. Zadeklaruj w dodanym module strukturę DaneOsobowe o polach Imię i Nazwisko typu
String oraz Wiek typu Integer.
4. Zadeklaruj w procedurze Main (Module1) zmienną doOsoba typu DaneOsobowe.
5. Zaprogramuj otwarcie pliku Osoby.dat w trybie do zapisu.
6. Utwórz pętlę Do z warunkiem While sprawdzanym na końcu; pętla powinna pracować w
nieskończoność – zostanie zakończona instrukcją Exit Do.
7. Zaprogramuj w pętli:
◦
pobranie od użytkownika imienia i przypisanie go polu Imię zmiennej doOsoba,
◦
sprawdzenie wartości pola doOsoba.Imię i jeśli:
◦
jest pustym łańcuchem znaków, pętla powinna się zakończyć – Exit Do,
◦
nie jest pustym łańcuchem znaków, pobranie nazwiska i wieku osoby i przypisanie ich
odpowiednim polom zmiennej doOsoba, wartości pól powinny następnie zostać zapi-
sane do pliku; użyj procedury WriteLine.
8. Zaprogramuj po zakończeniu pętli zamknięcie pliku i otwarcie go w trybie do odczytu.
9. Utwórz pętlę While z warunkiem sprawdzającym czy otwarty plik nie jest w pozycji końco-
wej.
10.Zaprogramuj w pętli While:
◦
odczyt kolejnych wartości z pliku i przypisanie ich odpowiednim polom zmiennej do-
Osoba,
◦
wyświetlenie wartości pól zmiennej doOsoba w konsoli.
11. Zaprogramuj po zakończeniu pętli While zamknięcie pliku.
12.Uruchom aplikację i wprowadź dane kilku osób.
Przykładowy efekt pracy aplikacji przedstawia rysunek:
W ćwiczeniu celowo użyto typu strukturalnego, aby zwrócić uwagę na uciążliwość wyprowadza-
nia wartości pól do pliku oraz ich odczytu z pliku. Wprawdzie konstrukcja
With
poprawia znacznie
sytuację, to jednak chciałoby się wyprowadzić do pliku wartość zmiennej doOsoba „za jednym zama-
chem”, a nie „na raty”.
Problem edycji pliku tekstowego byłby jeszcze bardziej skomplikowany. Konieczne byłoby wczy-
tanie wszystkich danych, edycja tych, które tego wymagają, utworzenie pliku i wyprowadzenie zmo-
dyfikowanych wartości. Pliki o dostępie swobodnym ułatwiają wykonanie takich zadań. Zaprojektowa-
nie aplikacji wykonującej identyczne zadanie, jak ta z ćwiczenia 122., na bazie plików o dostępie
swobodnym poprzedzimy ćwiczeniami wprowadzającymi do działań w tym trybie.
Najważniejszym wymaganiem przy pracy z plikami o dostępie swobodnym jest określona wiel-
kość porcji zapisywanych informacji. Oznacza, to, że zmienna, której wartość zapisujemy nie może
mieć dowolnego rozmiaru. Przyjrzyjmy się ostatnim dwóm wierszom przedstawionego wyżej przykła-
du występującym przed tekstem „Press any key to continue”. Widać, że liczba znaków występująca
w pierwszym z nich jest większa niż w drugim. Oznacza to, że zmienna doOsoba zajmowała więcej
bajtów gdy jej wartością była osoba o dłuższym imieniu. Dyskwalifikuje to zmienną doOsoba z wyko-
rzystania jej do pracy z plikami o dostępie swobodnym. Konieczne jest takie przygotowanie zmiennej,
aby jej wielkość była stała (podkreślmy wielkość, a nie zawartość). Wprowadzimy ograniczenie
na długość imienia i nazwiska (liczby typu Integer – Wiek – zawsze mają taki sam rozmiar). Do usta -
lenia („zafiksowania”) długości zmiennej typu
String
służy atrybut VBFixedString.
Przykład.
<VBFixedString(15)> Dim Imię As String
Zmienna Imię przechowywać będzie maksymalnie 15 znaków Jeśli liczba znaków w przypisy-
wanym łańcuchu przekracza ograniczenie, to tylko pierwsze 15 znaków znajdzie się w zmiennej.
Do otwierania plików o dostępie swobodnym stosuje się procedurę FileOpen, podając tryb
otwarcia OpenMode.Random. Pamiętamy, że procedura FileOpen posiada trzy opcjonalne parame-
try. Przy otwieraniu plików o dostępie swobodnym istotny jest ostatni, który przekazuje procedurze in -
formację o wielkości zapisywanych informacji. Parametr ten jest typu
Integer
, a jego wartość domyśl-
na to -1. Do określenia wielkości zapisywanej informacji można wykorzystać funkcję Len. Pamięta-
Rysunek 54: Projekt_122 w działaniu.
my, że funkcja zdefiniowana jest w module Strings i pierwotnie używaliśmy jej do określania długości
łańcucha tekstowego. Funkcja posiada dwanaście przeciążonych wersji, które dla zmiennych róż-
nych typów zwracają liczbę bajtów zajmowanych przez zmienną danego typu.
Podsumowując, aby skorzystać ze swobodnego dostępu do plików musimy:
utworzyć zmienne o stałej wielkości; jeśli w skład zmiennej wchodzi pole typu String, to należy
zafiksować jego długość wykorzystując atrybut VBFixedString,
znać stałą wielkość zmiennej; można ją obliczyć wykorzystując jedną z wersji funkcji Len,
otworzyć plik podając w procedurze FileOpen tryb OpenMode.Random i jako ostatni parametr
stałą wielkość porcji zapisywanej informacji.
Wymagania te zostaną spełnione w kolejnym ćwiczeniu.
Ćwiczenie 123
Zaprojektować aplikację pozwalającą utworzyć plik o dostępie swobodnym
przechowujący dane osobowe.
1. Utwórz projekt aplikacji konsolowej.
2. Dodaj do projektu nowy moduł o nazwie Osoba.
3. Zdefiniuj strukturę DaneOsoboweStałyRozmiar o polach Imię i Nazwisko typu String po-
zwalających na przechowywanie do 15 znaków oraz Wiek typu Integer.
Przykład.
Structure DaneOsoboweSatłyRozmiar
<VBFixedString(15)> Dim Imię, Nazwisko As String
Dim Wiek As Integer
End Structure
4. Zadeklaruj w procedurze Main (Module1) zmienną dosrOsoba typu DaneOsoboweStały-
Rozmiar.
5. Zadeklaruj zmienną intWielkośćZapisu typu Integer i przypisz jej obliczoną przez funkcję
Len wielkość zmiennej dosrOsoba.
Przykład.
Dim intWielkośćZapisu As Integer = Len(dosrOsoba)
6. Zaprogramuj otwarcie pliku Osoby.rnd w trybie dostępu swobodnego, jako ostatni para-
metr użyj zmienną intWielkośćZapisu.
Przykład. Warto przypomnieć, że miejsca pominiętych parametrów opcjonalnych (czwartego i
piątego, w tym przypadku) wskazuje się przecinkami.
FileOpen(1, "Osoby.rnd", OpenMode.Random, , , intWielkośćZapisu)
7. Zaprogramuj zamknięcie pliku.
8. Uruchom aplikację dwukrotnie, każdorazowo sprawdź datę i godzinę utworzenia pliku.
Funkcja FileOpen tworzy plik, jeśli ten nie istnieje, w przeciwnym przypadku otwiera istniejący.
Po otwarciu pliku w trybie swobodnym istnieje możliwość przesyłania danych w obu kierunkach –
do pliku i z pliku – bez konieczności przełączania trybu. W pliku można przesuwać punkt zapisu (od-
czytu) w dowolne miejsce.
Po utworzeniu pliku pozycja zapisu (odczytu) to pozycja początkowa i posiada ona numer 1. Je -
śli nastąpi zapis do pliku porcji danych, to pozycja zapisu przesunie się. Ta nowa pozycja ma numer
2. Każda kolejna pozycja ma numer większy niż poprzednia. Numery pozycji pozwalają identyfikować
konkretne miejsca w pliku i przemieszczać się do nich. Jest to możliwe wyłącznie dlatego, że wiel-
kość zapisywanych porcji informacji jest stała.
Do zapisywania danych do plików o dostępie swobodnym służy procedura FilePut. Posiada
ona 14 przeciążonych wersji. Podstawowa postać wywołania procedury wygląda następująco:
FilePut(NumerPliku, ZmiennaDoZapisania)
W optymalnym przypadku, gdy zmienna ma taką wielkość, jak ta podana w procedurze
FileOpen (szósty parametr), obszar pliku wykorzystany jest całkowicie przez dane. Jeśli wielkość
zmiennej jest mniejsza, to wolny obszar pozostający po końcu zapisu, nie zostanie wykorzystany
do przechowywania danych. Oznacza to stratę przestrzeni w systemie plików. W przypadku, gdy
zmienna ma wielkość większą niż ustalona podczas otwierania pliku, wystąpi błąd.
Procedura FilePut posiada opcjonalny parametr typu
Integer
o wartości domyślnej -1. Para-
metr ten pozwala wskazać pozycję w pliku, na której ma zostać zapisana wartość zmiennej. Jeśli pa -
rametr jest pominięty, to zapis następuje w aktualnej pozycji (tej, którą punkt zapisu osiągnął po po -
przednim zapisie/odczycie, lub przemieszczeniu). Ważne jest to, że dane zapisane na pozycji poda-
nej w procedurze FilePut zostaną zastąpione przez informacje zapisane w zmiennej.
Podobnym ograniczeniom podlega odczyt realizowany przy użyciu procedury FileGet, która
posiada 13 przeciążonych wersji, a jej podstawowa postać jest następująca:
FileGet(NumerPliku, ZmiennaDoOdczytania)
Procedura może przyjąć trzeci parametr, który wskaże pozycję w pliku, z której dane należy od-
czytać. Pokazuje to, że dostęp do danych w plikach o dostępie swobodnym uzasadnia nazwę tego
trybu pracy z plikami – tak zapis, jak i odczyt mogą być realizowane w dowolnym miejscu pliku.
Dodatkowo, możliwe jest uzyskanie informacji o numerze aktualnej pozycji zapisu/odczytu,
a także przesunięcie tej pozycji. Do obliczenia numeru aktualnej pozycji służy funkcja Seek, której je-
dynym parametrem jest numer pliku. Do przemieszczenia pozycji w pliku służy dwuparametrowa pro-
cedura Seek. Jej pierwszym parametrem jest numer pliku, drugim – numer pozycji, którą ma zająć
w pliku miejsce zapisu/odczytu.
W kolejnym ćwiczeniu zrealizujemy zapis do pliku o dostępie swobodnym, wykorzystując jedno-
cześnie funkcję Seek do śledzenia położenia pozycji zapisu w pliku oraz procedurę Seek do prze-
mieszczania tej pozycji.
Ćwiczenie 124
Zaprogramować zapis do pliku danych przechowywanych w zmiennej strukturalnej.
1. Dodaj pusty wiersz pomiędzy instrukcjami FileOpen i FileClose.
2. Utwórz pętlę While wykonywaną w nieskończoność (zakończenie nastąpi w wyniku wy-
konania instrukcji Exit While) i zaprogramuj w niej:
◦
wyświetlenie w konsoli numeru aktualnej pozycji zapisu w pliku,
Przykład.
Console.Writeline("Pozycja zapisu w pliku ma numer {0}", Seek(1))
◦
pobranie od użytkownika imienia i przypisanie go polu Imię zmiennej dosrOsoba,
◦
zakończenie pętli While, jeśli w polu Imię znajduje się pusty łańcuch, a w przeciwnym
przypadku:
▪
pobranie nazwiska i wieku oraz przypisanie ich polom zmiennej dosrOsoba,
▪
zapis do pliku wartości zmiennej dosrOsoba.
Przykład.
FilePut(1, dosrOsoba)
3. Zaprogramuj po zakończeniu pętli While:
◦
przesunięcie pozycji zapisu/odczytu do miejsca o numerze 1,
Przykład.
Seek(1, 1)
◦
przypisanie polom Imię i Nazwisko zmiennej dosrOsoba tekstu „Zmieniony”,
◦
zapis do pliku wartości zmiennej dosrOsoba.
4. Uruchom aplikację, wprowadź kilka zestawów danych.
Dane zostały zapisane w pliku. Kolejne ćwiczenie polegać będzie na ich odczycie. Ponieważ
wśród 13. przeciążonych wersji procedury FileGet nie istnieje (z oczywistych powodów) taka, która
pozwala na odczyt z pliku danych typu
DaneOsoboweStałyRozmiar
, na korzyść projektu wykonywa-
nego w kolejnym ćwiczeniu nastąpi wyłączenie opcji Strict. Pozwoli to na wykorzystanie 13. wersji
procedury, która służy do pobierania wartości typu ValueType.
Ćwiczenie 125
Zaprogramować odczyt danych z pliku o dostępie swobodnym.
1. Wyłącz w pliku modułu opcję Strict, w tym celu:
◦
dodaj przed wierszem rozpoczynającym blok modułu (wiersz ze słowem Module i na-
zwą modułu) pusty wiersz,
◦
wpisz instrukcję Option Strict Off.
2. Dodaj pusty wiersz przed instrukcją zamykającą plik (FileClose).
3. Zaprogramuj przemieszczenie pozycji zapisu/odczytu do miejsca o numerze 1 (początek
pliku).
4. Utwórz pętlę While wykonywaną tak długo, jak długo plik nie jest w pozycji końcowej i za -
programuj w niej:
◦
wyświetlenie numeru aktualnej pozycji zapisu/odczytu,
◦
odczyt do zmiennej dosrOsoba danych z pliku,
◦
wyświetlenie wartości pól zmiennej dosrOsoba w konsoli.
5. Uruchom aplikację.
Przykładowy efekt działania aplikacji przedstawia rysunek:
Wprowadzanie danych do pliku zakończyło się po drugim zestawie danych. Pozycja zapisu zo-
stała ustawiona na miejsce o numerze 1, a polom Imię i Nazwisko zmiennej dosrOsoba został przypi-
sany tekst „Zmieniony”. Wartość zmiennej została zapisana do pliku na pierwszej pozycji. Po tym za -
pisie plik znalazł się w pozycji 2. Pozycja została następnie przesunięta na początek pliku i nastąpił
odczyt danych. Jako zadanie do samodzielnego rozwiązania pozostawia się ćwiczącym odpowiedź
na pytanie „Dlaczego Zmieniony Zmieniony ma 12 lat skoro Stefan Żeromski miał lat 19?”.
Przetwarzanie plików często jest długotrwałe i wiele współczesnych aplikacji wyświetla tzw. pa-
sek postępu – jego długość reprezentuje wykonaną część zadania. Przykładowo, jeśli w pliku znajdu-
je się 100 zapisów, a przetwarzany jest 19, to część wskaźnikowa zajmuje około 19% długości pa-
ska. W aplikacjach konsolowych częściej spotykanym rozwiązaniem jest wyświetlanie procentowego
wykonania zadania. Jednak chcąc wiedzieć jaki procent zapisów z pliku został już przetworzony ko -
nieczna jest wiedza na temat liczby zapisów w pliku. Liczbę tą można obliczyć dzieląc wielkość pliku
Rysunek 55: Projekt_123 w działaniu.
przez wielkość porcji danych. Wiemy już jak obliczyć wielkość porcji danych. Do obliczania wielkości
pliku służą dwie funkcje, zwracające wynik typu
Long
, o istotnie różnym zastosowaniu:
FileLen – pozwala obliczyć wielkość w bajtach pliku, przechowywanego w systemie plików,
o nazwie podanej jako parametr funkcji. W nazwie można umieścić literę napędu, a także na -
zwy katalogów. Należy pamiętać o tym, że funkcja zwraca wielkość pliku odczytaną z danych
zawartych w systemie plików. Oznacza to, że jeżeli plik, którego wielkość odczytujemy, jest
otwarty, to obliczona wielkość pliku nie odzwierciedla zmian wprowadzonych w pliku od mo-
mentu otwarcia. Innymi słowy, funkcja zwraca wielkość pliku zapisaną w chwili ostatnio wyko-
nanego zamknięcia pliku.
LOF – pozwala obliczyć wielkość w bajtach pliku, otwartego przez procedurę FileOpen. Jedy-
nym parametrem funkcji jest numer otwartego pliku. Funkcja zwraca aktualną wielkość pliku.
Z powyższego wyszczególnienia wynika, że wartości zwracane przez obie funkcje mogą się
różnić. Zostanie to zaprezentowane w kolejnym ćwiczeniu.
Ćwiczenie 126
Zapoznać się z możliwością obliczania wielkości pliku przed jego otwarciem, oraz w
czasie gdy pozostaje otwarty.
1. Utwórz projekt aplikacji konsolowej.
2. Zdefiniuj w części deklaracyjnej modułu:
◦
stałe:
▪
BajtówNaInteger typu Integer o wartości 4, liczby typu Integer przechowywane są
w obszarze o wielkości 4 bajtów,
▪
NazwaPliku typu String o wartości „Dane.int”,
▪
Format typu String o wartości „Plik {0} ma wielkość {1} bajtów, zawiera {2} liczb
całkowitych.”, format ten będzie użyty przy wyprowadzaniu wyników obliczeń na
konsolę,
Przykład.
Const Format As String = "Plik {0} ma wielkość {1} bajtów, zawiera {2} liczb całkowitych."
▪
CzteryBackSpace typu String o wartości: vbBack & vbBack & vbBack & vbBack,
stała ta posłuży do usuwania w konsoli czterech znaków wyprowadzonych jako
ostatnie;
Przykład.
Const CzteryBackSpace As String = vbBack & vbBack & vbBack & vbBack
◦
procedurę Wypisz o dwóch parametrach przekazywanych przez wartość:
▪
Plik typu String,
▪
Wielkość typu Long,
działanie procedury powinno polegać na wypisaniu w konsoli informacji przekazanych przez parame-
try.
Przykład.
Console.WriteLine(Format, Plik, Wielkość, Wielkość \ BajtówNaInteger)
◦
bezparametrową procedurę Otwórz, w której zaprogramuj:
▪
otwarcie pliku o nazwie przechowywanej w zmiennej NazwaPliku w trybie dostępu
swobodnego, ustalając wielkość porcji zapisu (odczytu) na wartość przechowywa-
ną w stałej BajtówNaInteger,
▪
wyświetlenie w konsoli informacji o tym, że plik został otwarty;
◦
bezparametrową procedurę Zamknij, w której zaprogramuj:
▪
zamknięcie pliku,
▪
wyświetlenie w konsoli informacji o tym, że plik został zamknięty.
3. Zadeklaruj w procedurze Main (Module1):
◦
zmienne:
▪
longWielkośćPliku typu Long, posłuży do przechowywania wyniku obliczenia wiel-
kości pliku,
▪
intLiczba typu Integer, posłuży do przechowywania liczby całkowitej odczytanej
z pliku.
4. Zaprogramuj:
◦
otwarcie pliku, użyj procedury Otwórz,
◦
pętlę For, której zmienna sterująca zmienia się od 1 do 10000, a w niej zaprogramuj:
▪
wyprowadzenie do pliku (FilePut) wartości losowej z przedziału 500000
÷
1000000,
▪
konstrukcję warunkową, której instrukcje wykonywane są tylko wtedy, gdy wartość
zmiennej sterującej pętlą For jest wielokrotnością liczby 5000 (użyj operatora
Mod), a w niej zaprogramuj:
•
obliczenie wielkości otwartego pliku i przypisanie wyniku zmiennej longWielko-
śćPliku,
Przykład.
longWielkośćPliku = LOF(1)
•
użycie procedury Wypisz do wyświetlenia informacji o wielkości pliku i liczbie
danych w pliku;
Przykład.
Wypisz(NazwaPliku, longWielkośćPliku)
◦
zamknięcie pliku, po zakończeniu pętli For, użyj procedury Zamknij,
◦
obliczenie wielkości zamkniętego pliku o nazwie przechowywanej w zmiennej Nazwa-
Pliku i przypisanie wyniku zmiennej longWielkośćPliku,
Przykład.
longWielkośćPliku = FileLen(NazwaPliku)
◦
użycie procedury Wypisz do wyświetlenia informacji o wielkości pliku i liczbie danych
w pliku,
◦
otwarcie pliku,
◦
wyświetlenie w konsoli informacji o tym, że plik jest przetwarzany, użyj instrukcji Wri-
teLine konsoli,
◦
pętlę While, wykonywaną tak długo, jak długo otwarty plik nie znajdzie się w pozycji
końcowej, a w niej zaprogramuj:
▪
odczyt z pliku liczby całkowitej (FileGet) z przypisaniem jej wartości zmiennej in-
tLiczba,
▪
pętlę For wykonywaną tyle razy ile wynosi wartość zmiennej intLiczba; pętla nie
zawiera instrukcji;
▪
usunięcie z wiersza konsoli
czterech znaków, po zakończeniu pętli For; użyj in-
strukcji Write konsoli oraz stałej CzteryBackSpace,
Przykład.
Console.Write(CzteryBackSpace)
▪
wyświetlenie w konsoli stopnia przetworzenia pliku w procentach,
Przykład.
Console.Write("{0}%", Seek(1) * 100 * BajtówNaInteger \ longWielkośćPliku)
◦
zamknięcie pliku po zakończeniu pętli While; użyj procedury Zamknij.
5. Sprawdź działanie aplikacji.
9 Konsola posiada metody do przemieszczania kursora tekstowego (CursorLeft, CursorTop, SetCursorPosition). Użyto
stałej vbBack, aby wskazać możliwość użycia w konsoli znaków sterujących wydrukiem.
Przykładowy efekt działania aplikacji (uchwycono moment podczas przetwarzania pliku) może
być następujący:
Warto, jako samodzielne ćwiczenie, sprawdzić różnicę pomiędzy wielkością pliku o dostępie se-
kwencyjnym przechowującego 1000 liczb typu Integer a wielkością pliku Dane.int. Można też spróbo -
wać odpowiedzieć na pytanie, jaki warunek muszą spełniać liczby, aby plik Dane.int miał większy roz-
miar niż plik sekwencyjny.
Tryb swobodny posiada wiele zalet, jednak w przypadku gdy zapisywana struktura posiada pola
typu łańcuchowego mogą wystąpić dwa problemy. Po pierwsze, zafiksowany łańcuch tekstowy może
być zbyt krótki do przechowania informacji wprowadzanej przez użytkownika. W takim przypadku tra -
cimy część danych. Po drugie, jeśli długość zafiksowanego łańcucha przewiduje najdłuższy możliwy
tekst, to wszystkie teksty krótsze będą powodem nieoptymalnego wykorzystania przestrzeni zbioru
danych. W wielu przypadkach rozwiązaniem tych problemów będzie tryb binarny dostępu do plików.
IX.3.
Binarny tryb dostępu do plików
W omawianym trybie nie robi się żadnych założeń co do wielkości zapisywanej informacji.
Do otwierania plików służy procedura FileOpen. Jako tryb otwierania podaje się wartość OpenMo-
de.Binary i nie wyszczególnia się wielkości porcji zapisu/odczytu, jak to miało miejsce w trybie swo -
bodnym.
Przykład.
FileOpen(NumerPliku, NazwaPliku, OpenMode.Binary)
Do zapisu i odczytu służą procedury FilePut oraz FileGet. Liczba zapisanych bajtów równa
jest wielkości zmiennej użytej w procedurze FilePut, a liczba odczytanych bajtów równa jest wiel-
kości zmiennej użytej w procedurze FileGet.
Pliki otwarte w trybie binarnym można odczytywać bajt po bajcie, albo porcjami o innej, dowol-
nej wielkości.
W poprzednich ćwiczeniach zasadniczo występował jeden otwarty plik. Język Visual Basic 2010
pozwala na jednoczesne przetwarzanie 255 plików. Może się okazać, że wyznaczenie numeru
dla otwieranego pliku nastręcza pewnych trudności. Ułatwieniem może być funkcja FreeFile o wy-
niku typu
Integer
. Funkcja zwraca numer, który nie jest używany przez inne otwarte pliki. Jeśli wyko-
rzystane są wszystkie możliwe numery, to podczas wykonywania funkcji wystąpi błąd. W kolejnym
Rysunek 56: Projekt_126 w działaniu.
ćwiczeniu wykorzystana zostanie funkcja FreeFile do automatycznego przydziału numeru dla pli-
ków otwieranych w trybie binarnym; ćwiczenie ilustruje kopiowanie pliku.
Ćwiczenie 127
Wykorzystać tryb binarny do skopiowania pliku.
1. Utwórz projekt aplikacji konsolowej i zapisz go.
2. Skopiuj do katalogu bin\Debug utworzonego projektu plik Dane.int utworzony przez apli-
kację z ćwiczenia 126.
3. Zadeklaruj w procedurze Main zmienne intNumerPlikuKopiowanego, intNumerPlikuKopii
typu Integer oraz bytBajtDanych typu Byte. Pierwsze dwie zmienne posłużą do przecho-
wywania numerów przydzielonych plikom, trzecia będzie stanowić bufor, przez który
dane będą przenoszone z pliku kopiowanego do pliku kopii.
4. Zaprogramuj:
◦
wyznaczenie wolnego numeru dla otwieranego pliku i przypisanie go zmiennej intNu-
merPlikuKopiowanego,
Przykład.
intNumerPlikuKopiowanego = FreeFile()
◦
otwarcie pliku Dane.int w trybie binarnym,
Przykład.
FileOpen(intNumerPlikuKopiowanego, "Dane.int", OpenMode.Binary)
◦
wyznaczenie wolnego numeru dla otwieranego pliku i przypisanie go zmiennej intNu-
merPlikuKopii,
◦
otwarcie pliku Kopia.int w trybie binarnym,
◦
pętlę While wykonywaną tak długo, jak długo plik kopiowany nie osiągnął pozycji koń-
cowej, a w niej zaprogramuj:
▪
pobranie z pliku kopiowanego jednego bajta i przypisanie go zmiennej bytBajtDa-
nych,
Przykład.
FileGet(intNumerPlikuKopiowanego, bytBajtDanych)
▪
zapisanie wartości zmiennej bytBajtDanych do pliku kopii.
◦
zamknięcie, po zakończeniu pętli While, obu plików, wykorzystaj procedurę CloseFile
nie podając parametrów.
5. Uruchom aplikację, a po jej ukończeniu porównaj wielkości plików Dane.int i Kopia.int
(ciekawe informacje zawierają okna Właściwości – warto porównać wielkość Rozmiar
oraz Rozmiar na dysku
IX.4.
Procedury i funkcje związane z przetwarzaniem plików
W module FileSystem zdefiniowano, oprócz opisanych wcześniej procedur i funkcji, wiele me-
tod przydatnych podczas przetwarzania plików. W ćwiczeniu 119. do sprawdzenia czy istnieje plik
o określonej nazwie użyto funkcji Exists klasy File. Moduł FileSystem posiada funkcję Dir, która
może być wykorzystana w tym samym celu. Funkcja posiada dwie wersje: bezparametrową oraz
dwuparametrową. Wynik funkcji jest typu
String
.
Wersja dwuparametrowa przyjmuje jako pierwszy parametr łańcuch tekstowy, który może
przedstawiać dozwoloną ścieżkę dostępu do pliku (katalogu) i może zawierać znaki wieloznaczne „*”
oraz „?”. Drugi parametr przyjmuje jako wartość jedną z wartości enumeracji FileAttribute: Nor-
mal – 0, ReadOnly – 1, Hidden – 2, System – 4, Volume – 8, Directory – 16, Archive – 32. Wynik
funkcji Dir jest typu
String
i przedstawia pierwszy element systemu plików pasujący do wzorca prze-
kazanego jako pierwszy parametr i posiadający atrybuty przekazane przez drugi parametr.
Przykład. Zakłada się że strElement jest typu String.
strElement = Dir("*.*", FileAttribute.Normal)
Po wywołaniu, jak w przykładzie powyżej, zmienna strElement zawiera nazwę pliku o atrybucie
Normal, który znajduje się w katalogu aplikacji. Jeśli w katalogu nie ma żadnego pliku, to zmienna za-
wiera pusty ciąg znaków. Takie działanie funkcji Dir pozwala przeglądać iteracyjnie, lub rekurencyj-
nie dowolny katalog.
Bezparametrowa postać funkcji Dir może zostać zastosowana po wcześniejszym użyciu funk-
cji Dir z parametrami, wtedy wyszukuje takie elementy systemu plików, jakby posiadała parametry
wcześniej ustalone.
Przykład.
strElement = Dir("*.sys", FileAttribute.Hidden)
While strElement <> ""
Console.WriteLine(strElement)
strElement = Dir()
End While
Ponieważ w pierwszym wywołaniu funkcji Dir ustalono, że poszukiwane są pliki ukryte o na-
zwie z rozszerzeniem .sys, to kolejne (bezparametrowe) wywołania będą dotyczyły tylko takich pli-
ków, które pasują do ustalonych wcześniej parametrów. Kolejne ćwiczenie pokazuje przykład zasto-
sowania funkcji Dir.
10 Warto poszukać informacji o sposobie zapisu plików na dysku. Wiedza ta pozwala oszczędniej gospodarować prze-
strzenią dyskową.
Ćwiczenie 128
Zaprojektować aplikację wyświetlającą wszystkie pliki o nazwie config w katalogu
głównym dysku C:.
1. Utwórz projekt aplikacji konsolowej.
2. Zadeklaruj w procedurze Main zmienną strPlik typu String i przypisz jej wynik funkcji Dir
podając jako pierwszy parametr łańcuch tekstowy pasujący do nazwy „config” plików
umieszczonych w katalogu głównym dysku C:.
Przykład.
Dim strPlik As String = Dir("C:\config.*")
3. Utwórz pętlę While wykonywaną tak długo, jak długo zmienna strPlik nie zawiera pustego
łańcucha znaków i zaprogramuj w niej:
◦
wyświetlenie w konsoli wartości zmiennej strPlik,
◦
pobranie nazwy następnego pasującego do wzorca pliku i przypisanie jej zmiennej
strPlik.
Przykład.
strPlik = Dir()
4. Uruchom aplikację.
Efekt działania programu może być podobny do przedstawionego na rysunku:
Prześledźmy kolejne etapy wykonania aplikacji. W chwili deklarowania zmiennej strPlik wykony-
wana jest funkcja Dir, która przeszukuje katalog C:\. Zostaje odnaleziony pierwszy plik o nazwie pa-
sującej do wzorca, czyli config.kopia128 i jego nazwa przypisana zostaje do zmiennej strPlik. Para-
metry wywołania funkcji Dir są ustalone. W pętli zostaje sprawdzony warunek i okazuje się, ze
zmienna strPlik nie zawiera pustego łańcucha znaków – pętla będzie wykonywana. W pierwszej in-
strukcji pętli wyświetlona zostaje w konsoli wartość zmiennej strPlik. Następnie funkcja Dir poszuku-
je kolejnego pasującego do zapamiętanego wzorca pliku i przypisuje jego nazwę do zmiennej strPlik.
Pętla wykonywana jest tak długo, aż (po odnalezieniu ostatniego pliku pasującego do wzorca) funk-
cja Dir zwróci pusty łańcuch znaków.
Przy omawianiu funkcji Dir pojawiło się pojęcie atrybutu. Pliki tworzone w ćwiczeniach dotyczą-
cych dostępu sekwencyjnego, swobodnego, binarnego automatycznie otrzymywały atrybut Archive.
Istnieje możliwość zmiany atrybutów istniejącego pliku oraz możliwość odczytania atrybutów takiego
Rysunek 57: Projekt_128 w działaniu.
pliku. Do ustalania atrybutów pliku służy dwuparametrowa procedura SetAttr, której pierwszy para-
metr to łańcuch tekstowy określający plik, a drugi parametr określa atrybut pliku, który ma zostać
ustawiony (włączony). Drugi parametr przyjmuje jako wartość jedną ze stałych enumeracji FileAttribu-
te.
Przykład.
SetAttr("Nazwa.roz", FileAttribute.Hidden)
Po wykonaniu takiego wywołania plik Nazwa.roz będzie plikiem ukrytym. Możliwe jest ustawie-
nie więcej niż jednego atrybutu. Aby włączyć np. atrybuty Hidden i ReadOnly należy jako drugi para-
metr podać sumę wartości tych atrybutów.
Przykład.
SetAttr("Nazwa.roz", FileAttribute.Hidden + FileAttribute.ReadOnly)
Należy przy tym zauważyć, że wartości stałych zdefiniowanych w enumeracji FileAttribute są
potęgami liczby 2. W związku z tym, biorąc pod uwagę binarną reprezentację sumy tych atrybutów
można powiedzieć, że każdy dodany atrybut ustawia odpowiedni bit sumy. Przykładowo postać dwój-
kowa sumy użytej w przykładzie jest następująca:
(FileAttribute.Hidden + FileAttribute.ReadOnly)
B
↔
00000011
Do zagadnienia tego powrócimy za chwilę przy omówieniu odczytu atrybutów pliku. Do pobra-
nia atrybutów pliku istniejącego w systemie plików służy funkcja GetAttr. Jedynym parametrem tej
funkcji jest nazwa pliku, a wynik typu FileAttribute przedstawia zestaw ustawionych atrybutów pliku.
Przykład. Zakłada się, że faAtrybuty jest typu FileAttribute.
faAtrybuty = GetAttr(NazwaPliku)
Ponieważ funkcja zwraca wartość wynikającą ze wszystkich atrybutów pliku, potrzebny jest spo-
sób „wyłuskania” tych atrybutów. Załóżmy, że wartość binarna zmiennej faAtrybuty wynosi 00000011
(dziesiętne 3), to znaczy, że ustawione są atrybuty Hidden i ReadOnly pliku. Aby dowiedzieć się, czy
plik posiada atrybut ReadOnly posłużymy się wartością stałej ReadOnly (00000001). Iloczyn logiczny
(
And
) dwóch liczb daje w wyniku liczbę, w której ustawione są tylko te bity, które ustawione są w obu
liczbach wchodzących do iloczynu.
Przykład.
01010101
And 00000100
00000100
Widać, że jeśli oblicza się iloczyn dowolnej liczby i liczby, która posiada ustawiony tylko jeden
bit (nazywa się takie liczby maskami), w wyniku uzyskuje się albo zero, albo wartość maski. Stąd jeśli
iloczyn logiczny pewnej liczby i maski równy jest masce, to znaczy, że „maskowana” liczba posiada
ustawiony ten sam bit, który ustawiony jest w masce.
Zbiór stałych enumeracji FileAttribute spełnia warunki stawiane przed maskami. Każda stała ma
ustawiony inny (i tylko jeden) bit. Pozwala to na użycie tych stałych jako masek. Kolejne ćwiczenie
ilustruje ustawianie i odczyt atrybutów plików.
Ćwiczenie 129
Zaprojektować aplikację, która utworzy plik, wyłączy wszystkie jego atrybuty, a
następnie ustawi kolejno atrybuty Archive i ReadOnly. Po ustawieniu atrybutów
aplikacja powinna odczytać i wyświetlić informację o atrybutach utworzonego pliku.
1. Utwórz projekt aplikacji konsolowej.
2. Wyłącz opcję Strict w pliku modułu, przy włączonej opcji Strict konieczne byłoby użycie
jawnej konwersji sumy atrybutów na typ FileAttribute, np.
faAtrybuty = CType(faAtrybuty + FileAttribute.Archive, FileAttribute)
Uwaga. Sposób wyłączenia opcji Strict dla modułu przedstawiony jest w ćwiczeniu 125.
3. Zadeklaruj w procedurze Main zmienną faAtrybuty typu FileAttribute o wartości początko-
wej Normal.
4. Zaprogramuj utworzenie pliku Atrybuty.txt (otwarcie i zamknięcie pliku o podanej nazwie
skutkuje jego utworzeniem).
5. Ustaw atrybut Normal dla pliku Atrybuty.txt.
Przykład.
SetAttr("Atrybuty.txt", faAtrybuty)
6. Dodaj do zmiennej faAtrybuty wartość stałej Archive.
7. Ustaw ponownie atrybuty dla pliku.
8. Dodaj do zmiennej faAtrybuty wartość stałej ReadOnly.
9. Ustaw ponownie atrybuty pliku.
10.Przypisz zmiennej faAtrybuty wartość stałej Normal – pozwoli to dowieść, że odczytane
atrybuty pliku rzeczywiście były ustawione.
11. Odczytaj atrybuty pliku i przypisz odczytaną wartość zmiennej faAtrybuty.
Przykład.
faAtrybuty = GetAttr("Atrybuty.txt")
12.Utwórz konstrukcję warunkową, której instrukcje wykonane będą tylko wtedy, gdy zmien-
na faAtrybuty posiada ustawiony ten sam bit co stała ReadOnly.
Przykład. (Nawiasy użyto w celu poprawienia czytelności zapisu.)
If (faAtrybuty And FileAttribute.ReadOnly) = FileAttribute.ReadOnly Then
13.Zaprogramuj w konstrukcji warunkowej wyświetlenie informacji o tym, że plik posiada
atrybut „tylko do odczytu”.
14.Zaprogramuj drugą konstrukcję warunkową sprawdzającą czy plik posiada atrybut Archi-
ve i wyświetlającą informację o tym fakcie.
15.Uruchom aplikację.
Efekt działania aplikacji może być podobny do przedstawionego na rysunku:
Ostatnim elementem związanym z plikiem jest data i moment jego ostatniej modyfikacji. Do od-
czytu takich danych służy funkcja FileDateTime, której jedynym parametrem jest nazwa pliku, a
wynik (typu
DateTime
) zawiera szczegółowe dane. Kolejne ćwiczenie zapoznaje z działaniem funkcji
FileDateTime.
Ćwiczenie 130
Użyć funkcji FileDateTime w celu ustalenia daty ostatniej modyfikacji pliku.
1. Utwórz aplikację konsolową.
2. Zaprogramuj wyświetlenie w konsoli informacji o dacie ostatniej modyfikacji pliku Auto-
exec.bat.
Przykład.
Console.WriteLine("Plik Autoexec.bat został zmodyfikowany {0}.", _
FileDateTime("C:\Autoexec.bat").ToLongDateString)
3. Uruchom aplikację.
Efekt działania aplikacji może być podobny do przedstawionego na rysunku:
Rysunek 58: Projekt_129 w działaniu.
Rysunek 59: Projekt_130 w działaniu.