R13-T, Informatyka, ASP.NET


Rozdział 13.
Odczytywanie i zapisywanie plików na serwerze WWW

Odczyt i zapis plików jest niezwykle ważnym zagadnieniem ASP.NET. W poprzedniej części książki tworzyłeś już strony ASP.NET wykorzystujące pliki zewnętrzne (na przykład plik config.web, kod obsługi formularzy, pliki XML, itp.), jednak w tym rozdziale dowiesz się znacznie więcej o sposobie w jaki inne typy plików mogą powiększyć możliwości funkcjonalne aplikacji ASP.NET.

Istnieje bardzo wiele możliwości wykorzystania plików — bynajmniej nie ograniczają się one do przechowania danych zewnętrznych. W tym rozdziale omówione zostaną następujące zagadnienia:

Wykorzystanie plików w ASP.NET

Dzięki środowisku .NET wykorzystanie plików zewnętrznych (czyli plików z rozszerzeniem inne niż .aspx) w ASP.NET jest bardzo łatwe. W rzeczywistości, pliki te są konieczne, by aplikacje ASP.NET działały poprawnie. Do takich niezbędnych plików można zaliczyć web.config oraz global.asax kontrolujące sposób działania aplikacji.

Pliki zewnętrzne można także wykorzystać do zwiększenia możliwości funkcjonalnych ASP.NET. Poznałeś już kilka takich plików, na przykład własne elementy sterujące oraz przestrzenie nazw kompilowane do postaci bibliotek DLL. Pliki te zwiększają możliwości funkcjonalne tworzonych aplikacji ASP.NET, a jednocześnie umożliwiają zachowanie prostoty kodu źródłowego stron ASP.NET.

APS.NET pozwala także na korzystanie z plików, które w ogóle nie stanowią części aplikacji lecz mogą się w niej przydać. Do plików tego typu można zaliczyć pliki zawierające informacje tekstowe, importowane pliki z nagłówkami informacyjnymi, pliki zawierające informacje o aplikacji, pliki z życiorysami, oraz wszelkie inne pliki, które w jakikolwiek sposób mogą się okazać przydatne. ASP.NET pozwala na dostęp i wykorzystanie całego systemu plików serwera, a zatem możliwości są ogromne.

Dołączanie zawartości plików zewnętrznych

Jednym ze sposobów wykorzystania plików w ASP.NET jest, tak zwane, dołączanie plików. Sposób ten przypomina pobranie zawartości jednego pliku i umieszczenie jej wewnątrz drugiego pliku; na szczęście jednak, programista nie musi tego robić samemu. Sposoby przedstawione w kilku kolejnych podrozdziałach pokazują różne metody dołączania plików dostępne w ASP.NET.

Server-Side Includes

Server-Sice Includes (dołączanie plików po stronie serwera, w skrócie SSI) jest sposobem oddzielania kodu od tworzonej strony. Metoda jest przydatna w sytuacjach gdy chcemy wielokrotnie używać wybranego fragmentu kodu, bądź uprościć edycję stron.

Składnia pozwalająca na dołączanie kodu tą metodą ma następującą postać:

<!--#include file="nazwaPliku"-->

lub

<!--#include virtual="nazwaPliku"-->

Słowo kluczowe virtual służy do określenia nazwy dołączanego pliku przy wykorzystaniu ścieżki wirtualnej, natomiast słowo kluczowe file umożliwia podanie ścieżki dostępu do pliku w lokalnej strukturze folderów. Na przykład, jeśli byś chciał dołączyć zawartość pliku o adresie http://twoj.serwer.com.pl/includes/plik1.aspx do strony ASP.NET o adresie http://twoj.serwer.com.pl/folder1/folder2/strona.aspx, mógłbyś w tym celu wykorzystać jedno z dwóch poniższych poleceń #include:

<!--#include file="../../includes/plik1.aspx"-->

lub

<!--#include virtual="/includes/plik1.aspx"-->

Zwróć uwagę, iż użyte polecenie #include file będzie miało różną postać w zależności do położenia strony, w której będzie umieszczana zawartość dołączanego pliku. Określenie pliku wykorzystywane w takim poleceniu nazywamy względną ścieżką dostępu do pliku. Używanie takich ścieżek może być denerwujące, zwłaszcza gdy strony wykorzystujące polecenie #include znajdują się w różnych folderach. Z tego właśnie powodu ASP.NET umożliwia także dołączanie plików na podstawie bezwzględnych ścieżek dostępu — służy do tego polecenie #include virtual przedstawione na drugim przykładzie. Umożliwia ono określenie położenia dołączanego pliku w sposób niezależny od położenia pliku, do którego zostanie on dołączony.

Umieśćmy zatem nagłówek w pliku, który będziemy mogli dołączyć do wielu różnych stron ASP.NET. W tym celu, w pierwszej kolejności należy stworzyć stronę ASP.NET o nazwie header.aspx i umieścić w niej następujący kod:

<a href="index.aspx"><img src="header.gif" alt="Strona główna"></a><hr>

<a href="index.aspx">Strona główna</a> <a href="logout.aspx">Wyjdź</a>

Nie należy umieszczać w tym pliku żadnych innych znaczników, jak na przykład elementy <form> — zostaną one umieszczone w kodzie strony, do której plik header.aspx będzie dołączany. Kolejną czynnością będzie stworzenie w tym samym folderze kolejnej strony ASP.NET i dołączenie do niej nagłówka:

<script language="VB" runat="server">

sub Page_Load(obj as object, e as eventargs)

end sub

</script>

<html><body>

<!--#include file="header.aspx"-->

Witamy!

</body></html>

ASP.NET wstawi zawartość pliku header.aspx zanim zostaną przetworzone jakiekolwiek polecenia ASP.NET. Z tego względu, gdy strona będzie już gotowa do wykonania, środowisko ASP.NET będzie uważało iż jej kod ma następującą postać:

<script language="VB" runat="server">

sub Page_Load(obj as object, e as eventargs)

end sub

</script>

<html><body>

<a href="index.aspx"><img src="header.gif" alt="Strona główna"></a><hr>

<a href="index.aspx">Strona główna</a> <a href="logout.aspx">Wyjdź</a>

Witamy!

</body></html>

Postać strony, po wyświetleniu w przeglądarce, przedstawiłem na rysunku 13.1.

0x01 graphic

Rysunek 13.1. --> Zawartość plików dołączanych po stronie serwera jest traktowana tak, jak gdyby stanowiła część wykonywanej strony ASP.NET[Author:p8R]

Notatka
Należy pamiętać, że wszystkie opisywane czynności są wykonywane na serwerze, zanim jakiekolwiek informacje zostaną przesłane do przeglądarki. Zawartość wszystkich plików jest łączona ze sobą na serwerze zanim zostanie wykonany jakikolwiek kod ASP.NET i zanim cokolwiek zostanie przesłane do klienta. Dzięki temu, wywołania metody
Response.Redirect będą działać poprawnie.

Polecenia #include można umieszczać w dowolnych miejscach stron ASP.NET, oznacza to, iż przedstawiony w powyższym przykładzie nagłówek, równie dobrze mógłby być dołączony jako stopka. W dołączanym pliku można by także umieścić znaczniki <html> oraz <body>, jak również elementy sterujące wykonywane na serwerze.

Ostrzeżenie
Domyślnie polecenie
#include można używać wyłącznie w plikach o rozszerzeniach .shtml, .shtm, .stm, .asp, .asa, .asax oraz .aspx. Polecenie to umieszczone w kodzie strony HTML nie zostanie przetworzone. Rozszerzenia plików obsługujących mechanizm Server-Side Includes można określać w Internet Services Managerze — programie zarządzającym serwerem IIS 5.0.

Server-Side Includes a inne sposoby dołączania plików

Możesz się zastanawiać nad różnicą pomiędzy technologią Server-Side Includes a elementami sterującymi tworzonymi przesz użytkowników. Oba te rozwiązania można wykorzystywać w tych samych celach — od wydzielania fragmentów interfejsu użytkownika. Różnica pomiędzy nimi polega na tym, iż elementy sterujące służą wyłącznie do tworzenia fragmentów interfejsu użytkownika, natomiast SSI można używać w różnych celach, między innymi do wydzielenia i zapisania w jednym miejscu często wykorzystywanych funkcji i stałych.

Zazwyczaj, w przypadku wydzielania elementu interfejsu użytkownika, lepiej jest posłużyć się elementem sterującym, gdyż można w nim wykorzystać elementy programistyczne; SSI nie daje tej możliwości.

Tak

Nie

SSI należy się posługiwać jeśli chcemy dołączać do tworzonych stron często wykorzystywane elementy programistyczne, takie jak klasy lub funkcje.

Nie należy używać SSI gdy chcemy dołączyć do strony wyłącznie element interfejsu użytkownika. W takim przypadku lepszym rozwiązaniem będzie wykorzystanie elementów sterujących tworzonych przez użytkownika.

Inne sposoby dołączania plików

Środowisko ASP.NET udostępnia także inne sposoby dołączania plików. Większość z nich została już przedstawiona we wcześniejszych częściach książki. Kod obsługi formularzy omówiłem w rozdziale 6, pt.: „Ciąg dalszy wiadomości na temat tworzenia formularzy internetowych”. Informacje na temat dyrektywy Import znajdziesz natomiast w rozdziale 2 — pt.: „Tworzenie stron ASP.NET”. I w końcu, w rozdziale 5. — pt.: „Podstawowe wiadomości o tworzeniu formularzy internetowych” — opisałem tworzenie elementów sterujących użytkownika.

Wszystkie te metody różnią się sposobem implementacji, lecz każda z nich zapewnia możliwość dołączania do stron ASP.NET zawartości innych plików.

Dostęp do plików

Przestrzeń nazw System.IO udostępnia wiele możliwości funkcjonalnych, z których można korzystać przy tworzeniu stron ASP.NET. Do możliwości tych należy zaliczyć odczytywanie i zapisywanie plików, tworzenie i usuwanie folderów oraz sprawdzanie atrybutów plików i folderów. Możliwości funkcjonalne udostępniane przez tę przestrzeń nazw pozwalają także na wykonywanie czynności w odpowiedzi na zdarzenia związane z systemem plików, takie jak stworzenie lub usunięcie folderu przez innego użytkownika.

Pliki, strumienie, czytelnicy i pisarze

Nim zaczniemy poznawać klasy dostępne w przestrzeni nazw System.IO oraz operować na plikach, należy przedstawić różnicę pomiędzy plikami i strumieniami. Zagadnienie to jest ważne, gdyż zarówno pliki jak i strumienie są w ASP.NET czymś zupełnie innym.

Nowe określenie

Z technicznego punktu widzenia plik jest kolekcją danych, której nadano nazwę i zapisano w unikalnym miejscu na dowolnie długi okres czasu. Na przykład, pliki przechowywane na dysku twardym Twojego komputera posiadają nazwę i ścieżkę dostępu, a możesz z nich korzystać w każdej chwili gdy tylko będziesz tego potrzebować. Możesz wyobrażać sobie plik jako pudełko zawierające różne rzeczy — realny obiekt.

Nowe określenie

Natomiast ze strumieniem nie jest skojarzona żadna nazwa pliku, ścieżka dostępu ani też miejsce przechowywania. Strumień może zostać wykorzystany do odczytania lub zapisu danych z dowolnego miejsca, na przykład pliku, sieci czy też pamięci. A zatem strumień jest sposobem zapewnienia dostępu do dowolnych informacji, w tym także do plików. Gdy otwierasz i odczytujesz zawartość pliku, w rzeczywistości jest przy tym wykorzystywany strumień. Dostępnych jest wiele różnych typów strumieni, lecz wszystkie one są klasami potomnymi klasy Stream.

Strumienie zapewniają binarny dostęp do danych — odczytują one nieprzetworzone informacje w formie zer i jedynek. Taki sposób dostępu do danych może być przydatny, lecz w ASP.NET bardziej interesuje nas korzystanie z informacji zapisanych w kodzie Unicede — czyli z łańcuchów znaków, a nie ciągów zer i jedynek.

Środowisko .NET udostępnia dwie klasy służące właśnie do tego celu — TextReader oraz TextWriter. Nie będę ich tu szczegółowo opisywał, jednak należy wiedzieć iż dziedziczy po nich wiele innych klas. Przykładami klas potomnych kas TextReader oraz TextWriterXmlTextReader oraz XmlTextWriter przedstawione w rozdziale 11., pt.: „Użycie XML w ASP.NET”; a w tym rozdziale poznasz kilka kolejnych.

A zatem dysponujemy już dwiema niezależnymi kategoriami klas — Stream oraz klasami potomnymi zapewniającymi dostęp do danych binarnych oraz TextReader i TextWriter (oraz ich klasami potomnymi) zapewniającymi dostęp do danych tekstowych. Poznając środowisko .NET bez żadnych trudności można określić do której z tych kategorii należy interesująca nas klasa. Klasy i obiekty dziedziczące po klasie Stream mają zazwyczaj w nazwie słowo „stream”; na przykład: FileStram, MemoryStram, itp. Z kolei klasy dziedziczące po klasach TextReader oraz TextWriter mają zazwyczaj w nazwach słowa „reader” lub „writer”; na przykład: XmlTextReader, XmlTextWriter, itd.

Na szczęście dostępne są także klasy umożliwiające konwersję danych binarnych na tekstowe. Dwie takie klasy — StreamReader oraz StreamWriter — niezwykle ważne dla operacji na plikach w ASP.NET, zostaną opisane w dalszej części tego rozdziału. Rysunek 13.2 ilustruje wzajemne zależności pomiędzy tymi wszystkimi klasami.

Rysunek 13.2. Wzajemne relacje pomiędzy klasami Stream (i klasami potomnymi) oraz klasami TextReader i TextWriter (i ich klasami potomnymi)

Opis rysunku

Use these .NET object — Posłuż się następującymi obiektami .NET

To access… — Aby uzyskać dostęp do następujących źródeł danych

Memory — Pamięć

Networks — Sieci

Files — Pliki

Pozostałe (Stream, MemoryStream, TextReader…) bez zmian

Notatka
Nie należy mylić strumieni, czyli klasy
Stream oraz jej klas potomnych, ze strumieniowaniem. Strumienie pozwalają na uzyskanie dostępu do miejsc w których przechowywane są informacje, natomiast strumieniowanie to metoda dynamicznego pobierania danych, kawałek po kawałku, gdy są potrzebne. Strumienie można porównać z rzeczownikiem, natomiast strumieniowanie z czasownikiem — strumienie mogą, choć nie muszą, być strumieniowane.

Nowe określenie

Klasa Stream pozwala na asynchroniczny dostęp do danych. Oznacza to, że podczas wykonywania operacji na plikach, jednocześnie mogą być realizowane inne czynności. Na przykład, w przypadku zapisu informacji do bardzo dużego pliku co prawdopodobnie będzie trwać dosyć długo, plik ten można otworzyć asynchronicznie i zapisywać w nim dane w tle, a jednocześnie wykonywać kod, który przekieruje użytkownika w inne miejsce witryny.

Przeciwieństwem dostępu asynchronicznego jest dostęp synchroniczny. W tym przypadku, aby wykonać kolejny fragment kodu, realizacja poprzedniego fragmentu musi się zakończyć. Wykorzystanie tego trybu dostępu do plików może doprowadzić do pogorszenia efektywności działania aplikacji. Różnice pomiędzy sposobem wykonywania operacji przy wykorzystaniu dostępu asynchronicznego i synchronicznego, zostały zilustrowane na rysunku 13.3. W tym rozdziale przedstawię wyłącznie synchronicznych dostęp do danych; więcej informacji na temat dostępu asynchronicznego znajdziesz w dokumentacji środowiska .NET.

Rysunek 13.3. Asynchroniczny sposób wykonywania czynności często powoduje poprawienie efektywności działania aplikacji.

Opis rysunku

Time — Czas

Asynchronous — Dostęp asynchroniczny

Synchronous — Dostęp synchroniczny

General code — Wcześniejszy kod programu

Other operations — Inne czynności

File operations — Operacje na plikach

Continuing… — Kolejne czynności

Określanie właściwości plików i folderów

W tej części rozdziału skoncentrujemy się na czterech klasach: File i Directory oraz FileInfo oraz DirectoryInfo. Pierwsze dwie z nich udostępniają metody służące do tworzenia, modyfikacji oraz usuwania plików i folderów; a pozostałe — właściwości umożliwiające określanie atrybutów plików i folderów. Przykład wykorzystania obiektów tych klas przedstawiony został na listingu 13.1.

Listing 13.1. Wyświetlanie informacji o plikach i folderach

Analiza

Zapisz powyższy kod w pliku o nazwie listing1301.aspx. W pierwszym wierszu strony importowana jest dodatkowa przestrzeń nazwa — System.IO. W wierszu 5. tworzona jest nowa kopia obiektu FileInfo zawierającego informacje o naszym przykładowym pliku (dzięki temu możemy mieć pewność, że analizowany plik będzie istniał). Być może przypominasz sobie, że w rozdziale 4., pt.: „Stosowanie obiektów ASP.NET w językach C# i VB.NET” została przedstawiona metoda Server.MapPath, która odwzorowuje ścieżkę wirtualną na fizyczną. W wierszach od 8. do 14. są wyświetlane informacje na temat analizowanego pliku. Wyniki wykonania powyższego przykładu przedstawione zostały na rysunku 13.4.

0x01 graphic

Rysunek 13.4. Wyświetlanie informacji o plikach i folderach

W wierszu 17. tworzony jest obiekt DirectoryInfo. Przy jego tworzeniu wykorzystana została właściwość Directory, określająca folder w którym jest przechowywany analizowany plik. Następnie, w wierszach od 20. do 26. wyświetlane są informacje na temat wybranego folderu. Jak widać, obiekty FileInfo oraz DirectoryInfo mają wiele bardzo podobnych właściwości.

Ostrzeżenie
Jeśli wybrany plik nie będzie istnieć, to zostanie zgłoszony błąd. Przy wykorzystaniu metody
FileExists klasy File, można sprawdzić czy wybrany plik istnieje czy nie.

Podobnie, przy użyciu metody DirectoryExists klasy Directory można sprawdzić czy wskazany folder jest poprawny.

Obiekty klas File oraz Directory dysponują także kolekcją Attributes, za pośrednictwem której można uzyskać dodatkowe informacje o pliku lub folderze, na przykład, czy jest on przeznaczony tylko do odczytu bądź ukryty. Wszystkie dostępne atrybuty zebrane zostały w tabeli 13.1.

Tabela 13.1. Atrybuty i wartości plików i folderów

Atrybut

Wartość

Readonly

1

Hidden

2

System

4

Directory

16

Archive

32

Encrypted

64

Normal

128

Temporary

256

SparseFile

512

ReparsePoint

1024

Compressed

2048

OffLine

4096

NotContentIndexed

8192

Określając właściwości poszczególnych plików i folderów wartości te są do siebie dodawane. Na przykład, wykonanie poniższego kodu dla pliku listing1301.aspx:

Response.Write(f.Attributes)

spowoduje wygenerowanie łańcucha znaków "32", co oznacza iż plik ten jest archiwalny. Aby określić atrybuty pliku wystarczy zsumować wybrane wartości z tabeli 13.1 i przypisać je właściwości Attributes. Na przykład, aby sprawić że nasz przykładowy plik będzie ukryty, systemowy, skompresowany, zaszyfrowany i nie indeksowany, wystarczy wykonać następującą instrukcję:

f.Attributes = 10306

Ostrzeżenie
Nie można bezpośrednio określać wartości poszczególnych atrybutów. Na przykład, poniższa instrukcja:

f.Attributes.Hidden = 2

spowoduje zgłoszenie błędu. Atrybut Hidden jest bowiem stałą i nie można go modyfikować. Atrybuty można zmieniać wyłączenie, za pośrednictwem właściwości Attributes, na przykład:

f.Attributes = 2

Zapamiętanie wartości poszczególnych atrybutów może przysporzyć dużo problemów. A zatem, znacznie lepszym rozwiązaniem jest posługiwanie się nazwami odpowiednich stałych oraz operatorem BitOr:

f.Attributes = FileAttributes.Hidden BitOr _

FileAttributes.Compressed BitOr _

FileAttributes.NotContentIndexed

Wykonanie powyższego fragmentu kodu ma ten sam efekt co przypisanie właściwości Attributes wartości 10306. BitOr to jeden z grupy operatorów bitowych dostępnych w języku VB.NET; pozwala on na porównywanie wartości bitowych. Innymi operatorami zaliczającymi się do tej grupy są: BitAnd, BitNot oraz BitXor. Aby określić czy dla analizowanego pliku jest ustawiony wybrany atrybut, należy posłużyć się operatorem BitAnd:

if f.Attributes BitAnd FileAttriubutes.Hidden > 0 then

Response.Write("Ukryty")

end if

Powyższe możliwości doskonale nadają się do wyświetlania informacji o jednym pliku bądź folderze. Co jednak zrobić, jeśli będziemy musieli wyświetlić więcej informacji dotyczących, na przykład, wszystkich plików w pewnym folderze? Otóż klasa DirectoryInfo udostępnia dwie metody — GetFiles oraz GetDirectories — które zwracają kolekcje obiektów FileInfo oraz DirectoryInfo. Przykład wykorzystania tych kolekcji przedstawiłem na listingu 13.2.

Listing 13.2. Wyświetlanie informacji o wszystkich plikach i folderach we wskazanym folderze

Analiza

W wierszu 7. pobierane są informacje o wszystkich plikach w bieżącym folderze. W tym celu wywoływana jest ࡭etoda GetFiles("*.*"), gdzie *.* oznacza dowolny łańcuch znaków, po którym jest umieszczona kropka, a po niej dowolny łańcuch znaków (czyli, przykładowo, listing1302.aspx). Metoda ta zwraca kolekcję, a zatem bez problemów można wykorzystać element sterujący DataGrid, aby wyświetlić zawarte w niej informacje w wybrany przez nas sposób. W wierszu 10. wywoływana jest metoda GetDirectories, która zwraca informacje o wszystkich folderach znajdujących się w bieżącym folderze. Informacje te są wyświetlane podobnie jak informacje o plikach, przy wykorzystaniu elementu sterującego DataGrid. Wyniki wykonania powyższego przykładu przedstawione zostały na rysunku 13.5.

0x01 graphic

Rysunek 13.5. Prezentacja informacji zawartych w kolekcjach plików i folderów

Informacje z obu kolekcji można by także pobrać przy wykorzystaniu pętli for, jednak element sterujący DataGrid udostępnia znacznie wygodniejszy mechanizm prezentacji danych. Do pobrania i wyświetlenia informacji o wszystkich podfolderach można by użyć funkcji rekurencyjnej.

Stwórzmy teraz nieco bardziej przydatny przykład. Stworzymy przeglądarkę plików, której będzie można użyć do przeglądnięcia zawartości całego dysku twardego, podobnie jak Eksploratora Windows. Strona ta powinna dawać użytkownikom możliwość wyświetlania zawartości folderów i poruszania się po ich strukturze (podobnie jak Eksplorator Windows), jak również pozwalać na podanie nazwy wybranego folderu, co usprawni poruszanie się po zawartości dysku. Kod strony ASP.NET o powyższych możliwościach funkcjonalnych przedstawiony został na listingu 13.3.

Listing 13.3. System poruszania się i prezentacji zawartości systemu plików — listing1303.aspx

Analiza

Zapisz powyższy kod w pliku o nazwie listing1303.aspx. Za pierwszym razem gdy użytkownik wyświetli tę stronę w przeglądarce, zostanie wyświetlona zawartość folderu głównego (w tym przypadku C:\). W wierszu 9. pobierana jest wartość parametru żądania o nazwie dir — służy ona do określenia folderu, którego zawartość należy wyświetlić.

Jeśli parametr dir nie został podany (co ma miejsce podczas pierwszego wyświetlenia strony), to wyświetlana jest zawartość folderu domyślnego — C:\. W wierszu 16. tworzony jest nowy obiekt DirectoryInfo zawierający informacje dotyczące bieżącego folderu, w wierszu 15., w polu tekstowym jest wyświetlana nazwa tego folderu (poprzez określenie wartości właściwości Text pola tekstowego); a w wierszu 17. — wywoływana procedura ListFiles.

Procedura ListFiles, której kod rozpoczyna się w wierszu 31., pobiera po kolei wszystkie elementy kolekcji folderów bieżącego obiektu DirectoryInfo. Wcześniej jednak, w wierszu 34., procedura sprawdza czy znajdujemy się na głównym poziomie dysku. Jeśli nie, to konieczne będzie wyświetlenie połączenia "..", które umożliwi przejście do folderu nadrzędnego. W tym celu tworzony jest nowy obiekt HyperLink, który wyświetla na stronie łańcuch znaków ".." i kojarzy z nim adres URL bieżącej strony APS.NET z łańcuchem zapytania zawierającym ścieżkę do folderu nadrzędnego. Gdy użytkownik kliknie to połączenie, wykonywana jest ta sama strona, lecz przekazany do niej w łańcuchu zapytania parametr dir będzie zawierać nową ścieżkę dostępu — w tym przypadku ścieżkę do folderu nadrzędnego. Procedura obsługi zdarzenia Page Load wykorzysta tę ścieżkę do stworzenia nowego obiektu DirectoryInfo. W wierszu 41. tworzony jest nowy obiekt LiteralControl, który służy do dodania znacznika <br> pod połączeniu do folderu nadrzędnego.

Dla każdego folderu wykonywana jest ta sama, jedna czynność — tworzony jest element sterujący Hyperlink odsyłający użytkownika z powrotem do tej samej strony ASP.NET. Element ten wyświetla na stronie krótką nazwę folderu (patrz wiersz 46.) i dodaje jego pełną nazwę do łańcucha zapytania (w wierszu 47.). Nasz przykładowa strona używa tego parametru do wyświetlenia zawartości nowego folderu. W wierszu 51. ponownie jest tworzony obiekt LiteralControl, który dodaje znacznik <br> po połączeniu.

W wierszach do 54. do 56. pobierane są po kolei wszystkie nazwy plików przechowywanych w aktualnie przetwarzanym folderze. Nazwy te są następnie wyświetlane przy wykorzystaniu etykiety. Zanim przeanalizujemy ostatnią procedurę umieszczoną w naszej przykładowej stronie — tbDir_Handle — przyjrzymy się fragmentowi kodu strony definiującemu jej interfejs użytkownika. Został on przedstawiony na listingu 13.4.

Listing 13.4. Kod definiujący interfejs użytkownika strony prezentującej zawartość systemu plików — listing1303.aspx

Analiza

Nasza przykładowa strona ASP.NET zawiera trzy elementy — element sterujący TextBox wyświetlający ścieżkę dostępu do bieżącego folderu, Panel zawierający elementy sterujące HyperLink oraz etykietę (element sterujący Label) służący do wyświetlania nazw plików oraz wszelkich innych komunikatów tekstowych. Jeśli zawartość pola tekstowego ulegnie zmianie (co zapewne się stanie gdy użytkownik samemu poda nazwę folderu), zostanie wywołana procedura tbDir_Handle obsługująca zdarzenie TextChanged.

Kod tej procedury został przedstawiony na listingu 13.3, w wierszach od 21. do 29. Pobiera ona tekst zapisany w polu tekstowym i wykorzystuje go do określenia nowego folderu. Należy zwrócić uwagę na instrukcję if umieszczoną w wierszu 23. Otóż za każdym razem gdy użytkownik ma możliwość własnoręcznego podania jakichkolwiek informacji, warto upewnić się, że są one poprawne. W tym przypadku wykorzystywana jest metoda DirectoryExists, która sprawdza czy podana ścieżka wskazuje istniejący folder. Jeśli ścieżka nie jest prawidłowa, to zostanie wyświetlony stosowny komunikat. Podobne testy są niezwykle istotne, szczególnie w aplikacjach tego typu.

W końcu, jeśli podana ścieżka jest poprawna, ponownie wywoływana jest procedura ListFiles, która wyświetla zawartość nowego folderu. Wyniki wykonania tej strony zostały przedstawione na rysunku 13.6.

0x01 graphic

Rysunek 13.6. Przykładowy listing zawartości folderu wykonany przy użyciu naszej przykładowej aplikacji

Nie wspominałem jeszcze o dwóch zagadnieniach związanych z tą aplikacją. Pierwszym z nich jest wykorzystanie metody Server.URLEncode. Otóż za każdym razem gdy tworzony jest nowy obiekt Hyperlink i określany łańcuch zapytania, wywoływana jest także metoda Server.URLEncode. Zapewnia ona, że wszelkie znaki specjalne zostaną odpowiednio zakodowane do postaci łańcuchów znaków, które nie spowodują powstania nieprawidłowego adresu URL. Na przykład, gdyby ścieżka dostępu do pliku miała postać c:\Program Files\temp.txt, to odstęp pomiędzy słowami „Program” i „Files” mógłby spowodować wystąpienie błędów. Po wywołaniu metody Server.URLEncode ścieżka ta zostanie zamieniona do następującej postaci:

c%3a%5cprogram+files%5ctemp.txt

Wszystkie znaki, które nie mogą występować w adresie URL znakami, które protokół HTTP akceptuje i traktuje jako zamienniki.

Kolejnym zagadnieniem o którym jeszcze nie pisałem, są różne sposoby wywoływania naszej przykładowej strony ASP.NET. W procedurze Page_Load sprawdzamy czy strona została wyświetlona po raz pierwszy. Jeśli nie, będzie to oznaczało, iż użytkownik zmienił bieżący folder poprzez kliknięcie któregoś z elementów sterujących Hyperlink (nie powodują one przesłania formularza, a jedynie przekierowanie do wskazanej strony). W takim przypadku należy wykonać procedurę Page_Load i wyświetlić zawartość wskazanego folderu. Jeśli okaże się, że strona nie została wyświetlona po pierwszy lecz w efekcie żądania przesłanego z tej samej strony, to do wyświetlenia zawartości bieżącego folderu należy użyć procedury tbDir_Handle. Sprawdzenie tego warunku jest niezwykle istotne, gdyż bez niego zawartość folderu mogłaby zostać wyświetlona dwukrotnie.

Otwieranie plików

ASP.NET udostępnia kilka sposobów otwierania plików, które można wykorzystywać w zależności od zaistniałych okoliczności. Zgodnie z informacjami podanymi wcześniej, ASP.NET umożliwia otwieranie plików w celu odczytu zarówno danych binarnych jak i tekstowych (w przypadku ASP.NET zapisanych w kodzie Unicode). Tryb odczytu danych binarnych pozwala na bezpośrednie odczytywanie poszczególnych bitów tworzących plik. Unicode jest pewnym schematem umożliwiającym przekształcenie tych bitów w coś co my — ludzie — możemy łatwo odczytać; na przykład w cyfry i litery. Ponieważ dostęp do danych binarnych nie będzie nam potrzebny, skoncentrujemy się na operowaniu na danych tekstowych.

Użycie obiektów klasy --> FileInfo[Author:p8R]

Jednym ze sposobów otwierania plików jest użycie obiektów FileInfo. Po stworzeniu kopii takiego obiektu i skojarzeniu go z plikiem o podanej nazwie, można wykorzystać kilka metod służących do otwierania plików. Wybór konkretnej metody będzie zależał od tego, co chcemy zrobić z zawartością pliku. Wszystkie dostępne metody zostały przedstawione w tabeli 13.2.

Tabela 13.2. Metody Open klasy FileInfo

Metoda

Opis

Open

Otwiera plik przy wykorzystaniu podanych uprawnień i zwraca obiekt Stream.

OpenRead()

Zwraca strumień do pliku umożliwiający wyłącznie odczyt jego zawartości.

OpenText()

Zwraca obiekt StreamReader dla danego pliku.

OpenWrite()

Zwraca obiekt Stream umożliwiający zarówno odczyt jak i zapis informacji w pliku.

Metody te trzeba omówić nieco szerzej. W pierwszej kolejności przyjrzyjmy się typom dostępnych uprawnień.

W wywołaniu metody Open można podać trzy argumenty — FileMode, FileAccess oraz FileShare (w podanej kolejności). Pierwszy z nich — FileMode — informuje system operacyjny w jaki sposób należy otworzyć plik, na przykład czy zawartość istniejącego pliku ma być usunięta, czy też należy dopisać do nie nowe informacje zapisywane w pliku. Dostępne tryby otwierania plików zostały przedstawione w tabeli 13.3.

Tabela 13.3. Dostępne wartości argumentu FileMode

Tryb

Opis

Append

Otwiera plik jeśli istnieje i przechodzi na jego koniec. Jeśli plik nie istnieje, to tworzony jest nowy plik. Ten tryb otwierania plików może zostać wykorzystany tylko w przypadku otwierania plików z uprawnieniem do zapisu (Write — za chwilę go opiszę).

Create

Tworzy nowy plik bądź „nadpisuje” istniejący plik (usuwa jego aktualną zawartość).

CreateNew

Tworzy nowy plik.

Open

Otwiera istniejący plik.

OpenOrCreate

Otwiera plik jeśli istnieje, a w przeciwnym razie tworzy nowy.

Truncate

Otwiera istniejący plik, a następnie skraca go do długości 0 bajtów, co w rezultacie powoduje usunięcie całej jego aktualnej zawartości.

Argument FileAccess określa przywileje dostępu do pliku. Dostępne wartości tego atrybutu to: Read, ReadWrite oraz Write; odpowiednio otwierają plik w trybie do odczytu, odczytu i zapisu bądź tylko do zapisu.

Ostatni argument — FileShare — określa co się stanie jeśli dwa procesy jednocześnie spróbują uzyskać dostęp do tego samego pliku; na przykład, jeśli dwie osoby wyświetlą stronę WWW i w tej samej chwili spróbują zmienić zawartość pliku. Wartość tego argumentu ma wpływ na proces, który spróbuje uzyskać dostęp do pliku jako drugi. Wartości te są takie same jak wartości argumentu FileAccess, z jedną różnicą — dostępny jest dodatkowa wartość None, która informuje, że w danej chwili plik może być wykorzystywany tylko przez jeden proces.

Być może zauważyłeś, że wszystkie metody Open klasy FileInfo za wyjątkiem metody OpenText, zwracają obiekty Stream dające wyłącznie możliwość odczytu danych binarnych. Oczywiście do naszych celów nie jest to dobre. W dalszej części rozdziału, podczas prezentacji zagadnień związanych z odczytywaniem zawartości plików, pokażę jak ominąć ten problem.

Przedstawiony poniżej fragment kodu pokazuje w jaki sposób można otworzyć plik przy wykorzystaniu obiektu FileInfo:

'tworzymy obiekty FileInfo i StreamRader

dim objFile as new FileInfo(Server.MapPath("log.txt"))

dim objReader as StreamReader

'otwieramy plik

objReader = objFile.OpenText()

'inne czynności

'zamykamy strumień

objReader.close

Można także wykorzystać metodę Open:

dim objFile as new FileInfo(Server.MapPath("log.txt"))

dim objStream as Stream

objStream = objFile.Open( FileMode.OpenOrCreate, FileAccess.Read )

Użycie obiektów klasy FileStream

Klasa FileStream pozwala na tworzenie strumieni umożliwiających dostęp do plików. Jedną z zalet wykorzystania obiektów FileStream jest to, iż nie stwarzają one konieczności wcześniejszego użycia obiektów FileInfo. Niemniej jednak należy się upewnić, iż plik do którego chcemy uzyskać dostęp naprawdę istnieje. Nie było to konieczne w przypadku posługiwania się obiektami FileInfo, gdyż sam fakt pomyślnego utworzenia takiego obiektu oznaczał istnienie pliku. Poniższy fragment kodu pokazuje w jaki sposób można otworzyć plik przy wykorzystaniu obiektu FileStream:

dim objF as new FileStream(Server.MapPath("log.txt"), _

FileMode.OpenOrCreate)

Powyższe wywołanie otwiera plik w trybie OpenOrCreate. Konstruktor klasy FileStream wykorzystuje te same argumenty co metoda Open klasy FileInfo, z tym iż pierwszym argumentem wywołania musi być łańcuch znaków określający nazwę otwieranego pliku.

Klasa FileStream udostępnia także metodę Seek, która umożliwia przejście do dowolnego miejsca strumienia (na przykład, na jego początek lub koniec). Składnia wywołania tej metody ma następującą postać:

Seek(przesunięcie, punktOdniesienia)

Argument przesunięcie określa odległość na jaką należy przejść względem podanego punktuOdniesienia. Argumentem punktOdniesienia może być jedną z wartości typu wyliczeniowego SeekOrigin: SeekOrigin.Begin (oznacza, że przesunięcie będzie liczone od początku pliku), SeekOrigin.Current (oznacza, że przesunięcie będzie liczone względem bieżącego położenia w pliku) oraz SeekOrigin.End (oznacza, że przesunięcie będzie liczone względem końca pliku). Na przykład, poniższy fragment kodu powoduje przejście na początek, a następnie na koniec pliku:

'przechodzimy na początek pliku

objF.Seek( 0, SeekOrigin.Begin )

'przechodzimy na koniec pliku

objF.Seek( 0, SeekOrigin.End )

Odczyt plików

Teraz, kiedy już wiesz jak należy otwierać pliki, możemy zająć się odczytywaniem ich zawartości. W ASP.NET czynność ta jest wykonywana głównie przy wykorzystaniu obiektów klasy StreamReader. Zgodnie z tym co zostało podane wcześniej, obiekty tej klasy konwertują dane binarne do postaci tekstowej, dzięki czemu otrzymujemy znaki oraz łańcuchy znaków, którymi należy posługiwać się na stronach ASP.NET. Stworzenie obiektu klasy StreamReader jest bardzo proste:

dim objReader as new StreamReader(obiekt)

Argumentem obiekt może być obiekt Stream (na przykład obiekt FileStream utworzony w poprzedniej części rozdziału) bądź ścieżka dostępu do konkretnego pliku. Stwórzmy teraz prosty plik, którego będziemy używali w dalszych przykładach; będzie on nosił nazwę log.txt i należy zapisać go w folderze /aspnetdlakazdego/rozdzial13. Poniżej przedstawiłem zawartość tego pliku:

Zwinne lisy

przeskoczyły nad

leniwym

brązowym psem

Klasa StreamReader udostępnia kilka metod służących do odczytywania znaków z pliku. Pierwsza z nich — Read — odczytuje ze strumienia pojedynczy znak, zwraca go w formie liczby całkowitej i przechodzi do kolejnego znaku. Oto przykład jej wykorzystania:

dim f as new FileInfo(Server.MapPath("log.txt"))

dim objReader as StreamReader

objReader = f.OpenText

Response.Write(objReader.Read & "<br>")

objReader.Close

Wykonanie powyższego fragmentu kodu spowoduje wyświetlenie na stronie liczby 90, która jest wartością litery „Z” w kodzie ASCII. Kolejne wywołanie metody Read spowodowałoby wyświetlenie liczby 119, odpowiadającej w kodzie ASCII literze „w”. I tak dalej. Jednak liczby te nie są dla nas przydatne, a zatem należy przekształcić je do postaci znaków zapisanych w kodzie Unicode. Służy do tego metoda Chr klasy Strings:

Response.Write(Strings.Chr(objReader.Read) & "<br>")

Pierwsze wykonanie powyższego fragmentu kodu po otworzeniu strumienia powinno zwrócić literę „Z”, drugie „w” i tak dalej.

Jednak odczytywanie pojedynczych znaków może być nieco męczące, dlatego też klasa StreamReader udostępnia dwie inne metody, które zwracają całe łańcuchy znaków. Metodami tymi są: ReadLine (która odczytuje znaki aż do końca wiersza) oraz ReadToEnd (która odczytuje całą pozostałą zawartość strumienia). Poniżej przedstawiony został przykład użycia metody ReadToEnd:

dim objReader as new StreamReader(Server.MapPath("log.txt"))

Response.Write(objReader.ReadToEnd)

objReader.Close

Wykonanie powyższego fragmentu kodu spowoduje wyświetlenie łańcucha znaków:

Zwinne lisy przeskoczyły nad leniwym brązowym psem

A co się stało ze znakami końca wiersza? Jeśli przejrzysz kod HTML wygenerowanej strony, to zauważysz, że znaki te zostały w nim umieszczone. Niestety język HTML nie interpretuje znaków końca wiersza jako znaczników przełamania wiersza (<br>). Znaczniki te można umieścić w odpowiednich miejscach wykorzystując metodę ReadLine:

Response.Write(objReader.ReadLine & "<br>")

Metoda ta odczytuje jednak tylko jeden wiersz, a zatem, aby odczytać całą zawartość pliku konieczne będzie wykorzystanie pętli. Gdy dotrzesz do końca pliku, to próba odczytania kolejnych znaków przy użyciu metod Read lub ReadLine spowoduje zgłoszenie błędu. Na szczęście, klasa StreamReader udostępnia metodę Peek, która umożliwia uniknięcie tej przykrej sytuacji.

Metoda Peek odczytuje kolejny znak ze strumienia, lecz w rzeczywistości go nie zwraca — innymi słowy pozwala „podejrzeć” ten znak. Jeśli tym znakiem będzie koniec strumienia, to metoda zwraca wartość -1. Posługując się tą metodą można odczytać całą zawartość strumienia bez jakichkolwiek problemów:

dim objReader as new StreamReader(Server.MapPath("log.txt"))

while objReader.Peek() > -1

Response.Write(objReader.ReadLine & "<br>")

end while

objReader.Close

Wyniki wykonania powyższego fragmentu kodu przedstawione zostały na rysunku 13.7.

0x01 graphic

Rysunek 13.7. Odczytywanie zawartości strumienia przy użyciu metody ReadLine

Ostrzeżenie
Ponieważ metoda Peek nie odczytuje znaku ze strumienia, a zatem nie zmienia także bieżącego położenia w strumieniu, pamięta
nego przez obiekt StreamReader. Dlatego też konieczne jest wykorzystanie metod klasy StreamReader w celu przesunięcia bieżącego położenia w strumieniu, gdyż inaczej łatwo można stworzyć nieskończoną pętlę, której przykład został przedstawiony na poniższym przykładzie:

while objReader.Peek () > -1

Response.Write("<br>")

end while

Uruchomienie tego fragmentu kodu spowoduje próbę wykonania nieskończonej pętli, która powstaje gdyż bieżące położenie w strumieniu nigdy nie jest modyfikowane.

Do zwrócenia określonej ilości znaków ze strumienia można także użyć metody Read. W tym przypadku składnia wywołania tej metody ma następującą postać:

objReader.Read(char(), początek, ilość)

Ta wersja metody Read odczytuje ze strumienia podaną ilość znaków, rozpoczynając w miejscu określonym przy użyciu argumentu początek. Odczytane znaki zostają zapisane w tablicy typu Char przekazanej jako pierwszy argument wywołania metody. Oto przykład:

dim objReader as new StreamReader(Server.MapPath("log.txt"))

dim arrString(11) as Char

dim i as Byte

objReader.Read(arrString, 0, 11)

for i = 0 to Ubound(arrString) - 1

Response.Write(arrString(i))

next

objReader.Close

W wierszu 2. jest tworzona tablica typu Char, zapisywana w zmiennej arrString. W wierszu 5. jest wywoływana metoda Read, która odczytuje ze strumienia 11 znaków, rozpoczynając od jego początku. Znaki tez zostają zapisane w tablicy arrString. Wykonanie powyższego fragmentu kodu spowoduje wyświetlenie łańcucha znaków

Zwinne lisy

To dziesięć znaków i jeden odstęp (litera y jest ostatnim znakiem).

Wyobraź sobie, że w celach demonstracyjnych chcielibyśmy wyświetlić kod źródłowy jednej z naszych stron ASP.NET, tak aby użytkownicy witryny mogli go przeanalizować i, na przykład, poznać jedną z omawianych tu metod odczytu plików. Jednak jeśli użytkownik spróbuje odwołać się do strony ASP.NET przy użyciu przeglądarki WWW, to uzyska wyłącznie kod HTML — wszystkie instrukcje ASP.NET zostaną bowiem przetworzone i usunięte. A zatem to my będziemy musieli wyświetlić zawartość strony zanim zostanie ona przetworzona. Można to zrobić przy wykorzystaniu klas udostępnianych w przestrzeni nazw System.IO. Przykład takiej aplikacji przedstawiony został na listingu 13.5.

Listing 13.5. Wyświetlanie kodu źródłowego stron ASP.NET w przeglądarce.

Analiza

W procedurze Page_Load tworzony jest nowy obiekt FileStream, który posłuży nam do odczytania zawartości wybranego pliku. W wierszu 7. tworzony jest obiekt StreamReader, który umożliwia dostęp do zawartości pliku. Użycie znacznika <pre> sprawia, że formatowanie na wynikowej stronie WWW będzie przypominało oryginalny sposób formatowania wyświetlanego kodu. W dalszej części procedury wykonywana jest pętla while, która przy wykorzystaniu metod Peek oraz ReadLine wyświetla poszczególne wiersze pliku. Przy wyświetlaniu kodu odczytywanego z pliku używana jest także metoda Server.HTMLEncode, która zapewnia, że znaczniki HTML nie będą interpretowane. Na końcu procedury są zamykane obiekty StreamReader oraz FileStream oraz generowany zamykający znacznik </pre>. Wyniki wykonania powyższej strony ASP.NET zostały przedstawione na rysunku 13.8.

0x01 graphic

Rysunek 13.8. Wyświetlanie kodu źródłowego strony ASP.NET w przeglądarce

Zapis plików

Zapisywanie danych do strumieni umożliwiają obiekty klasy StreamWriter. Składnia instrukcji służącej do utworzenia takiego obiektu jest bardzo prosta. Obiekty tej klasy, podobnie jak obiekty StreamReader można utworzyć na postawie obiektu Stream bądź ścieżki dostępu określającej położenie pliku:

dim objWriter as new StreamWriter(FileStreamLubŚcieżka, dopisać)

Argument dopisać jest wartością logiczną (typu Boolean) określającą czy nowe informacje powinny zostać dopisane do istniejącej zawartości pliku. Jeśli argument ten przyjmie wartość false, to istniejąca zawartość pliku zostanie usunięta. Jeśli wskazany plik nie istnieje, zostanie on utworzony. Jeśli argument dopisać będzie miał wartość true, to wszystkie informacje zapisywane w pliku zostaną dodane na jego końcu, za istniejącą zawartością.

Klasa StreamWriter udostępnia dwie metody służące do zapisywania danych — Write oraz WriteLine. Oto przykład ich wykorzystania:

dim objWriter as new StreamWriter _

(Server.MapPath("log.txt"), true )

objWriter.WriteLine("Ale pies zupełnie")

objWriter.Write("się tym nie przejął")

objWriter.Close

W wierszu 1. tworzony jest obiekt StreamWriter skojarzony z plikiem log.txt, a jednocześnie informujemy, że nowe informacje mają być dopisywane do istniejącej zawartości pliku. W wierszach 4. i 5. zostają wywołane dwie metody służące do zapisu danych w pliku, po czym obiekt pisarza (StreamWriter) zostaje zamknięty. Po wykonaniu powyższego fragmentu kodu, zawartość pliku log.txt będzie miała następującą postać:

Zwinne lisy

przeskoczyły nad

leniwym

brązowym psemAle pies zupełnie

się tym nie przejął

Jak widać, po tekście zapisanym przy użyciu metody WriteLine został umieszczony znak nowego wiersza. Jednak oryginalna zawartość pliku oraz tekst dodany do niego przez nasz przykładowy program, nie są w żaden sposób oddzielone. Aby zapisać w pliku znak nowego wiersza, wystarczy wywołać metodę WriteLine nie podając w jej wywołaniu żadnych argumentów:

objWriter.WriteLine()

Obiekty StreamWriter wykorzystują bufor wyjściowy. Przypominasz sobie zapewne zagadnienia związane z buforowanie generowanych stron, opisane w rozdziale 4., pt.: „Stosowanie obiektów ASP.NET w językach C# i VB.NET”. Domyślnie, obiekty StreamWriter umieszczają dane w buforze przed przekazaniem ich do strumienia. Jeśli chcesz, aby dane były przesyłane do strumienia po każdym wywołaniu metody Write lub WriteLine, wystarczy przypisać właściwości AutoFlush obiektu StreamWriter wartość true.

Można także ręcznie przekazać zawartość bufora do strumienia, wywołują metodę Flush. Przypisanie właściwości AutoFlush wartości true może jednak sprawić, iż efektywność działania aplikacji będzie nieco lepsza. Automatyczne opróżnienie bufora (poprzez przypisanie właściwości AutoFlush wartości true) należy stosować, w sytuacji gdy użytkownicy oczekują natychmiastowych wyników. Na przykład, podczas zapisywania w pliku dużej ilości danych, w sytuacji gdy chcesz, aby użytkownicy mogli zobaczyć wprowadzane modyfikacje jeszcze przed zakończeniem przetwarzania pliku.

Inne operacje na plikach i folderach

Zarówno klasa File jak i Directory udostępniają metody służące do kopiowania, tworzenia, przenoszenia oraz usuwania plików i folderów. Ich użycie jest bardzo proste i nie wymaga większego komentarza. Metody te przedstawiłem w tabeli 13.4; dotyczą one zarówno klasy File jak i Directory, chyba że jawnie napisałem, że tak nie jest.

Tabela 13.4. Różne metody klas File i Directory

Metoda

Opis

--> Directory.CreateDirectories[Author:p8R]

Tworzy wszystkie foldery określone w podanej ścieżce.

Directory.CreateDirectory

Tworzy folder o określonej ścieżce. Jeśli w jakimkolwiek miejscu ścieżki zostanie użyty nieistniejący folder, to ASP.NET zgłosi błąd.

Directory.Delete

Usuwa folder. Drugi argument wywołania tej metody — rekurencyjnie — jest wartością logiczną, określającą czy należy także usunąć wszystkie podfoldery oraz pliki.

File.Copy

Kopiuje istniejący lub nowy plik. Trzeci argument wywołania tej metody — nadpisać — to wartość logiczna określająca czy istniejący plik powinien zostać nadpisany.

File.Create

Tworzy plik o określonej ścieżce dostępu.

File.CreateText

Tworzy nowy obiekt StreamWriter umożliwiający zapis danych w nowym pliku.

File.Delete

Usuwa plik.

--> File.ChangeExtension[Author:p8R]

Zmienia rozszerzenie pliku określonego przy użyciu podanej ścieżki. Aby usunąć rozszerzenie pliku, należy przypisać argumentowi rozszerzenie wartość nothing. Nie zapomnij zapisać kropki przez nowym rozszerzeniem. Ta statyczna metoda zwraca ścieżkę dostępu do pliku z nowym rozszerzeniem.

--> File.GetExtension[Author:p8R]

Ta statyczna metoda zwraca rozszerzenie pliku.

--> File.HasExtension[Author:p8R]

Ta statyczna metoda zwraca wartość true jeśli podany plik ma rozszerzenie.

Move

Przenosi wskazany plik lub folder określony jako staraŚcieżka w miejsce określone jako nowaŚcieżka.

Aby zmienić nazwę pliku lub folderu można go przenieść (przy użyciu metody Move) lub skopiować (metodą Copy) a następnie usunąć (przy użyciu metody Delete).

Podsumowanie informacji o plikach i folderach

Ze względu na fakt, iż ASP.NET udostępnia tak wiele różnych klas umożliwiających operowanie na systemie plików, wybór której z nich należy użyć może przysporzyć wielu problemów. W tabeli 13.5. przedstawiłem dostępne klasy oraz podałem informacje o ich przeznaczeniu.

Tabela 13.5. Klasy i typy wyliczeniowe zdefiniowane w przestrzeni nazw System.IO

Klasa

Kiedy należy używać obiektów tej klasy

BinaryReader oraz BinaryWriter

Służy do odczytywania i zapisywania informacji binarnych w strumieniach (na przykład dat oraz obiektów).

Directory

Pozwala na tworzenie, usuwanie oraz wykonywanie innych operacji na folderach.

File

Pozwala na tworzenie, usuwanie oraz wykonywanie innych operacji na plikach.

FileInfo oraz DirectoryInfo

Te klasy pozwalają na przeglądanie oraz określanie właściwości plików i folderów.

FileAttributes oraz DirectoryAttributes

Obiekty tych klas służą do określania atrybutów plików i folderów.

FileMode, FileAccess oraz FileShare

Typy wyliczeniowe określające uprawnienia i tryby otwierania plików.

FileStream

Ta klasa zapewnia dostęp do pliku wraz z możliwością przechodzenia w jego dowolne miejsce.

MemoryStream

Klasa ta zapewnia dostęp do strumieni umożliwiających zapis i odczyt danych nie z plików lecz pamięci komputera.

SeekOrigin

Typ wyliczeniowy, którego wartości są używane w wywołaniach metody FileStream.Seek.

StreamReader oraz StreamWriter

Klasy te pozwalają na --> odczyt i zapis odpowiednio zakodowanych znaków w strumieniach bajtowych[Author:p8R] .

StringReader oraz StringWriter

Klasy te pozwalają na odczyt i zapis danych w łańcuchach znaków. Ich możliwości funkcjonalne odpowiadają możliwościom klas StreamReader oraz StreamWriter.

Składowanie izolowane

Posługując się metodami przedstawionymi we wcześniejszej części rozdziału można zapisywać dane w pliku o unikalnej ścieżce dostępu, na przykład: c:\inetpub\wwwroot\aspnetdlakazdego\rozdzial13\log.txt. To bardzo potężna i użyteczna metoda przechowywania informacji; ma jednak jedną wadę.

Po pierwsze, dla każdego pliku konieczna jest znajomość lub stworzenie unikalnej ścieżki dostępu. Oczywiście, w przypadkach przedstawionych w tym rozdziale, nie stanowi to większego problemu; spróbuj jednak wyobrazić sobie aplikację która musi działać na różnych serwerach, z których każdy ma własną, unikalną strukturę systemu plików. Zarządzanie tymi wszystkimi plikami przechowywanymi w różnych miejscach może być prawdziwym utrapieniem.

Po drugie, z tworzonych w taki sposób plików mogą korzystać także inni użytkownicy oraz aplikacje, które mogą uzyskać dostęp do lokalnego systemu plików (czyli niemal każdy — od osoby odwiedzającej strony WWW poczynając, a na użytkowniku lokalnego komputera kończąc). To doskonała możliwość w przypadku plików zawierających, na przykład, informacje dotyczące licznika odwiedzin, do których powinni mieć dostęp wszyscy korzystający z aplikacji. Co jednak zrobić w sytuacji, gdy chcesz wykorzystać pliki do przechowywania prywatnych informacji o każdym z użytkowników? W takim przypadku trudno byłoby określić do kogo należą poszczególne informacje.

Wszystkie te problemy można jednak rozwiązać dzięki wykorzystaniu mechanizmu składowania izolowanego dostępnego w ASP.NET. Mechanizm ten, pod pewnymi względami, przypomina cookies, gdyż kojarzy dane z użytkownikami i izoluje je. Każdy użytkownik otrzymuje swój własny izolowany obszar składowania. Już nigdy nie trzeba będzie przejmować się określaniem unikalnych ścieżek dostępu do plików. Mechanizm składowania izolowanego umożliwia zapisywanie danych w obszarach, które fizycznie mogą być przechowywane w dowolnym miejscu, nawet na lokalnym komputerze użytkownika (zupełnie jak cookies).

Aby wykorzystać mechanizm składowania izolowanego, należy poznać kilka nowych zagadnień. Potem jednak, sposoby działania tego mechanizmu będą przypominać standardowe metody uzyskiwania dostępu do plików.

Tworzenie izolowanych obszarów składowania

W przypadku posługiwania się mechanizmem składowania izolowanego wykorzystywane są obiekty dwóch klas — IsolatedStorageFile oraz IsolatedStorageFileStream. Przypominają one obiekty File oraz FileStream przedstawione w poprzedniej części rozdziału. W rzeczywistości klasa IsolatedStorageFileStream udostępnia te same metody co klasa FileStream.

W odróżnieniu od obiektów File, obiekty IsolatedStorageFile nie reprezentują plików lecz raczej obszary umożliwiające przechowywanie danych. Pliki przechowywane w tych obszarach są reprezentowane przez obiekty klasy IsolatedStorageFileStream. Z początku różnice te mogą być nieco mylące, a zatem należy dobrze zrozumieć przeznaczenie obu tych klas.

Przeanalizujmy listing 13.6, który pokazuje w jaki sposób można stworzyć plik w izolowanym obszarze składowania

Listing 13.6. Tworzenie pliku w izolowanym obszarze składowania

Analiza

Zwróć uwagę, na wykorzystanie nowej przestrzeni nazw — System.IO.IsolatedStorage — importowanej w 3. wierszu. Nie zapomnij zaimportować jej także we własnych stronach ASP.NET. W wierszach od 7. do 9. są deklarowane używane zmienne, w tym także nowy obiekt klasy IsolatedStorageFileStream. Deklarowany w wierszu 8. obiekt StreamWriter, powinien już wyglądać znajomo.

Kolejny fragment kodu także nie powinien zawierać żadnych niespodzianek — jedyną wprowadzoną w nim nowością, jest użycie obiektu IsolatedStorageFileStream. Składania instrukcji służącej do stworzenia nowej kopii tego obiektu jest taka sama jak w przypadku tworzenia obiektów FileStream. W wierszach 13. i 14. wykonujemy znane już czynności posługując się przy tym obiektem StreamWriter; a w wierszu 15. zamykamy go, co powoduje także zamknięcie strumienia IsolatedStorageFileStream. I to by było wszystko.

Przedstawiony powyżej przykład tworzy plik o nazwie colors.txt i zapisuje go w izolowanym obszarze składowania należącym do bieżącego użytkownika. Gdyby inny użytkownik spróbował uzyskać dostęp do tego pliku, nie było by to możliwe; podobnie jak nie jest możliwe uzyskanie dostępu do cookies innego użytkownika. Konkretne miejsce, w którym mechanizm składowania izolowanego przechowuje pliki, zależy od używanego systemu operacyjnego. Informacje ta ten temat zostały przedstawione w tabeli 13.6.

Tabela 13.6. Domyślne foldery wykorzystywane przez mechanizm składowania izolowanego.

System operacyjny

Położenie

Windows 95, 98, Me

c:\Windows\Ustawienia lokalne\Dane aplikacji

Windows NT 4.0

c:\WinNT\Profile\<użytkownik>\Dane aplikacji

Windows NT 4.0 (z Service Pack 4) oraz Windows 2000 (uaktualnienie Win NT 4.0)

c:\WinNT\Profile\<użytkownik>\Ustawienia lokalne\Dane aplikacji

Windows 2000 (instalacja „czysta”, czyli bez uaktualniania innego systemu Windows — 95, 98, Me bądź WinNT 3.51)

c:\Documents and Settings\<użytkownik>\Ustawienia lokalne\Dane aplikacji

Na przykład, po wykonaniu strony z listingu 13.6 na serwerze IIS działającym w systemie Windows 2000 (zainstalowanym bez uaktualniania innych wersji systemu Windows), należy przejść do folderu c:\Documents and Settings\Default User\Ustawienia lokalne\Dane aplikacji\Microsoft. W folderze tym powinien znajdować się folder o nazwie IsolatedStorage. Wewnątrz niego powinny się znajdować inne foldery, wykorzystywane przez ASP.NET do przechowywania informacji o wykonywanych czynnościach, a oprócz nich — także plik colors.txt utworzony w wierszu 11. listingu 13.6. Zazwyczaj, to co się dzieje w tych folderach nie będzie miało najmniejszego znaczenia, jednak znajomość fizycznego położenia plików może się czasami okazać przydatna.

Dostęp do plików zapisanych w obszarach izolowanych

Dane przechowywane przy wykorzystaniu mechanizmu składowania izolowanego są separowane przy użyciu dwóch różnych metod: użytkownika i komponentu oraz użytkownika, komponentu i domeny. Użycie pierwszej metody oznacza, że izolowany obszar składowania będzie tworzony dla każdej aplikacji z której korzysta użytkownik. Na przykład, plik zapisany w obszarze izolowanym przez użytkownika A korzystającego z aplikacji A, nie będzie dostępny dla tego samego użytkownika korzystającego z aplikacji B. Druga metoda dodatkowo uwzględnia domenę aplikacji. W kontekście ASP.NET oznacza to po prostu adres URL aplikacji.

Być może przypominasz sobie, że strony ASP.NET są kompilowane do postaci dynamicznie generowanych komponentów .NET (informacje na ten temat podawałem w rozdziale 2). Oznacza to, że w normalnych okolicznościach, żadne dwie strony ASP.NET nie będą korzystały z tego samego komponentu .NET; a to z kolei oznacza, że żadne dwie strony ASP.NET nie mogą uzyskać dostępu do tego samego izolowanego obszaru składowania. Idea ta została przedstawiona na rysunku 13.9.

Rysunek 13.9. Ten sam użytkownik, używający dwóch różnych stron ASP.NET w tej samej aplikacji, nie będzie w stanie uzyskać dostępu do tego samego izolowanego obszaru składowania.

Opis rysunku

Store x — Obszar x

No access! — Brak dostępu

Web site — Aplikacja

Page x — Strona x

user 1 — Użytkownik 1

Do odczytywania danych przechowywanych w obszarach izolowanych wykorzystywane są obiekty klasy IsolatedStorageFileStream. Przykład ich użycia przedstawiony został na listingu 13.7.

Listing 13.7. Odczyt danych z obszarów izolowanych przy wykorzystaniu obiektów klasy IsolatedStorageFileStream

Kod powyższego listingu na pewno wygląda znajomo, gdyż nie ma w nim żadnych nowych metod. Wykonanie tej strony powinno spowodować wyświetlenie słowa „niebieski”, które zostało zapisane w pliku umieszczonym w obszarze izolowanym przez stronę z listingu 13.6.

Notatka
Zwróć uwagę, iż wykonania powyższej strony nie musi spowodować wyświetlenia jakichkolwiek wyników. Przypomnij sobie, że dwie różne strony ASP.NET nie mogą uzyskać dostępu do tego samego izolowanego obszaru składowania. Oznacza to, że strona z listingu 13.7 nie może korzystać z obszaru używanego przez stronę z listingu 13.6. Problem ten można rozwiązać umieszczając kody z obu list
ingów w jednym dokumencie (to samo dotyczy kodów przedstawionych na listingach 13.6 oraz 13.8).

Nieco inaczej wygląda sprawa w przypadku odczytywania danych przechowywanych w obszarach izolowanych, przy użyciu obiektów klasy IsolatedStorageFile. W tym przypadku, w pierwszej kolejności należy pobrać odwołanie do pliku przechowywanego w izolowanym obszarze składowania, a dopiero później można użyć obiektu klasy IsolatedStorageFile do wykonania jakichś operacji na tym pliku. Proces ten demonstruje przykład przedstawiony na listingu 13.8.

Listing 13.8. Odczyt danych z pliku przechowywanego w obszarze izolowanym przy użyciu obiektu IsolatedStorageFile

Analiza

W wierszach 8. i 9. tworzony jest obiekt IsolatedStorageFile. Metoda IsolatedStorageFile.GetUserStoreForDomain zwraca obiekt klasy IsolatedStorageFile wybrany dla danego użytkownika, komponentu oraz domeny. Metoda IsolatedStorageFile.GetUserStoreForAssembly zwraca natomiast obszar izolowany dla konkretnego użytkownika i komponentu.

Metoda GetFileNames zwraca tablicę zawierającą listę nazw plików spełniających podane kryteria; w naszym przypadku jest to "*.*". W wierszach od 13. do 16. wszystkie elementy tej tablicy są pobierane, a zapisane w nich nazwy plików są wyświetlane w elemencie sterującym Label. Podobne czynności wykonuje metoda GetDirectoryNames, która także umożliwia podanie łańcucha znaków określającego kryteria filtrowania zwracanych wyników.

W końcu, w wierszach od 18. do 25. są wyświetlane właściwości izolowanego obszaru składowania. Właściwość AssemblyIdentity zwraca URL określający komponent .NET któremu odpowiada dany izolowany obszar składowania (czyli dynamiczny komponent wygenerowany przez środowisko .NET dla aplikacji WWW). Właściwość DomainIdentity określa domenę skojarzoną z danym izolowanym obszarem składowania (przypomina ona nieco właściwość Domain obiektów reprezentujących cookies). Właściwości CurrentSize oraz MaxSize określają wielkość obszaru składowania należącego do bieżącego użytkownika, wyrażoną w bajtach. Wyniki wykonania powyższego kodu przedstawione zostały na rysunku 13.10.

0x01 graphic

Rysunek 13.10. Prezentacja informacji o izolowanym obszarze składowania, możliwa dzięki wykorzystaniu obiektu IsolatedStorageFile

Na podstawie obiektu IsolatedStorageFile można stworzyć obiekt IsolatedStorageFileStream, a następnie użyć obiektu StreamReader do odczytania zawartości wybranego pliku:

dim objISOFile as IsolatedStorageFile = _

IsolatedStorageFile.GetUserStoreForDomain()

dim stream as new IsolatedStorageFileStream _

("options.txt", FileMode.OpenOrCreate, objISOFile )

To nie jest ASP!

Operacje wejścia/wyjścia we wcześniejszych wersjach technologii ASP były wykonywane za pośrednictwem obiektów klasy FileSystem. Udostępniała ona te same możliwości funkcjonalne co klasy omówione w tym rozdziale. ASP.NET ma możliwość wykorzystania wszystkich klas dostępnych w środowisku .NET, co oznacza, że w odróżnieniu od wcześniejszych wersji technologii ASP, w ASP.NET można wykonywać te same operacje wejścia/wyjścia co w tradycyjnych, niezależnych aplikacjach.

Na szczęście, wiele rozwiązań stosowanych w ASP.NET, a nawet składnia ich implementacji, przypomina analogiczne rozwiązania używane we tradycyjnej wersji technologii ASP. Zmieniły się nazwy kilku klas oraz niewidoczne dla programistów sposoby implementacji niektórych możliwości funkcjonalnych; jednak programiści znający zasady posługiwania się obiektami klasy FileSystemObject nie powinni mieć problemów z przejściem do nowych metod wykorzystywania plików.

Jedną z najważniejszych zmian, jest przejście do całkowicie obiektowej architektury. W środowisku .NET każdy plik oraz folder może być reprezentowany przez obiekt, a każdy z tych obiektów udostępnia własne metody, właściwości oraz kolekcje dodatkowych obiektów. Przywyknięcie do stosowania tych ściśle ze sobą powiązanych obiektów może zabrać nieco czasu, zwłaszcza, iż znacznie różnią się one od obiektów FileSystemObject.

W ASP.NET zmieniły się także zasady dołączania plików. Dzięki metodom interakcji ASP.NET ze środowiskiem .NET, dołączania zawartości plików do aplikacji ASP.NET jest bardzo proste. Tradycyjna technologia SSI wciąż jest dostępna, jednak można wykorzystać wiele innych metod dołączania plików i rozszerzania w ten sposób możliwości funkcjonalnych stron ASP.NET.

Natomiast składowanie izolowane jest całkowicie nową metodą przechowywania danych i dostępu do plików. Eliminuje on wiele problemów napotykanych wcześniej przy tworzeniu rozwiązań służących do przechowywania informacji skojarzonych z użytkownikami. Oprócz cookies i baz danych, tradycyjna technologia ASP nie udostępniała żadnych wbudowanych metod służących do trwałego przechowywania danych skojarzonych z konkretnymi użytkownikami. Ale czemu rezygnować z zastosowania cookies? Otóż przy użyciu mechanizmu składowania izolowanego można przechowywać znacznie więcej informacji niż w cookies, co z kolei umożliwia znacznie dalej idące dostosowanie aplikacji do potrzeb i oczekiwań użytkowników. Poza tym mechanizm składowania izolowanego jest znacznie łatwiejszy do wykorzystania niż cookies, pliki przechowywane w ten sposób mogą być składowane zarówno na serwerze jak i na komputerze użytkownika, a co ważniejsze, rozwiązanie to udostępnia znacznie lepsze mechanizmy zabezpieczeń.

Przewaga mechanizmu składowania izolowanego nad bazami danych nie jest aż tak oczywista. Wykorzystanie jednego lub drugiego rozwiązania będzie zależeć od konkretnej sytuacji oraz konfiguracji serwera. Niemniej jednak obie te metody są niezwykle przydatne przy trwałym przechowywaniu danych.

Opisywane w tej części rozdziału metody Open są także dostępne w klasie File.

2 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

2 Dokument2

rysunek zamieszczony w oryginale książki ma się nijak do przykładu który ma ilustrować.

UWAGA!! WAŻNE!! Zarówno w tym, jak i w kolejnych podrozdziałach zmieniłem w tekście i przykładach odwołania do klasy (i obiektów) File na klasę FileInfo. Autor wyraźnie popełnił błąd, gdyż pisze i podaje przykłady tworzenia obiektów klasy File, a po prostu nie jest to możliwe, gdyż klasa ta nie udostępnia żadnego publicznego konstruktora. Wszystkie przykłady podane w tekście wykorzystujące tę klasę są błędne i w podanej przez autora postaci nie działają. Ponieważ autor we wszystkich przykładach tworzy obiekty i za ich pomocą odwołuje się do metod, zdecydowałem się na zamienienie klasy File klasą FileInfo. Oczywiście można by wykorzystać statyczne metody klasy File, lecz autor wyraźnie miał zamiar korzystać z obiektów - patrz 3. zdanie 1. akapitu kolejnego podrozdziału (pt. „Użycie obiektów FileStream”).

Wg. dokumentacji ASP.NET Beta2 nie ma takiej metody!!! Proponuję usunąć.

W specyfikacji .NET SDK beta 2 w klasie File nie ma tej metody. Proponuję usunąć.

W specyfikacji .NET SDK beta 2 w klasie File nie ma tej metody. Proponuję usunąć.

W specyfikacji .NET SDK beta 2 w klasie File nie ma tej metody. Proponuję usunąć.

Na podstawie opisu w dokumentacji .NET SDK.



Wyszukiwarka

Podobne podstrony:
R15-T, Informatyka, ASP.NET
R12-T, Informatyka, ASP.NET
R20-T, Informatyka, ASP.NET
R17-T, Informatyka, ASP.NET
R14-T, Informatyka, ASP.NET
R11-T, Informatyka, ASP.NET
R21-T, Informatyka, ASP.NET
informatyka asp net 3 5 tworzenie portali internetowych w nurcie web 2 0 omar al zabir ebook
informatyka asp net ajax programowanie w nurcie web 2 0 christian wenz ebook
informatyka asp net mvc 4 programowanie jess chadwick ebook
informatyka asp net mvc 3 framework zaawansowane programowanie steven sanderson ebook
BizAgi Studio Cz, 5 Stworzeni aplikacji zewn trznej w ASP NET
ASP NET 2 0 Tworzenie witryn internetowych z wykorzystaniem C i Visual Basica aspntw
asp net introduction MM6QQFHOGEVK7FULUA
C i ASP NET Szybki start
ASP NET Vademecum profesjonalisty
asp net introduction to microsoft asp net 3R522NRLFCX55WSTS6WZOFPHBH4HEKDTR3EY47Q

więcej podobnych podstron