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:
•
Sposoby użycia plików w ASP.NET oraz gdzie pliki te będą widziane.
•
Sposoby dołączania plików do stron ASP.NET.
•
Sposoby dostępu do właściwości plików i folderów.
•
Sposoby otwierania, odczytu i zapisu informacji w plikach.
•
Sposoby dostarczania wydzielonych obszarów przechowywania danych dla każdego z
użytkowników.
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.
Rysunek 13.1.
Zawartość plików dołączanych po stronie serwera jest traktowana tak, jak gdyby
stanowiła część wykonywanej strony ASP.NET
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
TextWriter
są
XmlTextReader
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.
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.
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
1
<%@ Import Namespace="System.IO" %>
2
<script language="VB" runat="server">
3
4
sub Page_Load(obj as object, e as eventargs)
5
dim f as new FileInfo(Server.MapPath("listing1301.aspx"))
6
7
lblMessage.Text = "Informacje o pliku<br>" & _
8
"<b>Nazwa: </b>" & f.Name & "<br>" & _
9
"<b>
Ś
cie
ż
ka: </b>" & f.DirectoryName & "<br>" & _
10
"<b>Czas ostatniego dost
ę
pu: </b>" & f.LastAccessTime & _
11
"<br>" & _
12
"<b>Czas ostatniego zapisu: </b>" & f.LastWriteTime & _
13
"<br>" & _
14
"<b>Długo
ść
: </b>" & f.Length & " bajtów<p>"
15
16
'powrót do folderu nadrz
ę
dnego
17
dim dir as DirectoryInfo = f.Directory
18
19
lblMessage.Text += "Informacje o folderze<br>" & _
20
"<b>Nazwa: </b>" & dir.Name & "<br>" & _
21
"<b>Pełna nazwa: </b>" & dir.FullName & "<br>" & _
22
"<b>Czas ostatniego dost
ę
pu: </b>" & dir.LastAccessTime & _
23
"<br>" & _
24
"<b>Czas ostatniego zapisu: </b>" & dir.LastWriteTime & _
25
"<br>" & _
26
"<b>Folder nadrz
ę
dny: </b>" & dir.Parent.Name & "<br>"
27
28
end sub
29
30
</script>
31
32
<html><body>
33
<asp:label id="lblMessage" runat=server/>
34
</body></html>
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.
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
1
<%@ Import Namespace="System.IO" %>
2
<script language="VB" runat="server">
3
sub Page_Load(obj as object, e as eventargs)
4
dim dir as new DirectoryInfo(Server.MapPath _
5
("/aspnetdlakazdego"))
6
7
DataGrid1.DataSource = dir.GetFiles("*.*")
8
DataGrid1.DataBind()
9
10
DataGrid2.DataSource = dir.GetDirectories
11
DataGrid2.DataBind()
12
13
end sub
14
15
</script>
16
17
<html><body>
18
<b>Informacje o plikach</b><br>
19
<asp:DataGrid id="DataGrid1" runat="server"
20
width="100%"
21
Font-Name="Arial"
22
Font-Size="10pt"
23
AlternatingItemStyle-Backcolor="#cccccc"
24
AutogenerateColumns="true" />
25
26
<p>
27
<b>Informacje o folderach</b><br>
28
<asp:DataGrid id="DataGrid2" runat="server"
29
width="100%"
30
Font-Name="Arial"
31
Font-Size="10pt"
32
AlternatingItemStyle-Backcolor="#cccccc"
33
AutogenerateColumns="true" />
34
</body></html>
Analiza
W wierszu 7. pobierane są informacje o wszystkich plikach w bieżącym folderze. W tym celu
wywoływana jest metoda
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.
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
1
<%@ Import Namespace="System.IO" %>
2
<script language="VB" runat="server">
3
private dir as DirectoryInfo
4
private f as FileInfo
5
private strDir as string
6
7
sub Page_Load(obj as object, e as eventargs)
8
if not Page.IsPostBack then
9
strDir = Request.Params("dir")
10
11
if strDir = "" then
12
strDir = "c:\"
13
end if
14
15
tbDir.Text = strDir
16
dir = new DirectoryInfo(strDir)
17
ListFiles()
18
end if
19
end sub
20
21
sub tbDir_Handle(obj as object, e as EventArgs)
22
strDir = obj.Text
23
if Directory.Exists(strDir) then
24
dir = new DirectoryInfo(strDir)
25
ListFiles()
26
else
27
lblMessage.Text = "Bł
ę
dna nazwa folderu"
28
end if
29
end sub
30
31
sub ListFiles()
32
dim hl as HyperLink
33
dim d as DirectoryInfo
34
if not dir.Root.FullName = dir.FullName then
35
hl = new HyperLink
36
hl.Text = ".."
37
hl.NavigateURL = "listing1303.aspx?dir=" & _
38
Server.URLEncode(dir.Parent.FullName)
39
Panel1.Controls.Add(hl)
40
41
Panel1.Controls.Add(new LiteralControl("<br>"))
42
end if
43
44
for each d in dir.GetDirectories
45
hl = new Hyperlink
46
hl.Text = d.Name
47
hl.NavigateURL = "listing1303.aspx?dir=" & _
48
Server.URLEncode(d.FullName)
49
Panel1.Controls.Add(hl)
50
51
Panel1.Controls.Add(new LiteralControl("<br>"))
52
next
53
54
for each f in dir.GetFiles("*.*")
55
lblMessage.Text += f.Name & "<br>"
56
next
57
end sub
58
</script>
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
1
<html><body>
2
<form runat="server">
3
<b>Foldery:</b>
4
<asp:Textbox id="tbDir" runat="server"
5
OnTextChanged="tbDir_Handle"
6
AutoPostBack=true /><p>
7
<asp:Panel id="Panel1" runat="server"
8
MaintainState="true" />
9
<asp:label id="lblMessage" runat=server
10
maintainstate=false />
11
</form>
12
</body></html>
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.
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
Jednym ze sposobów otwierania plików jest użycie obiektów
FileInfo
1
. 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.
1
Opisywane w tej części rozdziału metody
Open
są także dostępne w klasie
File
.
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.
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
ę
tanego 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.
1
<%@ Import Namespace="System.IO" %>
2
<script language="VB" runat="server">
3
sub Page_Load(obj as object, e as eventargs)
4
dim fs as new FileStream(Server.MapPath _
5
("listing1305.aspx"), FileMode.Open, FileAccess.Read)
6
dim objReader as new StreamReader(fs)
7
8
lblMessage.Text = "<pre>"
9
while objReader.Peek() > -1
10
lblMessage.Text += Server.HTMLEncode _
11
(objReader.ReadLine) & "<br>"
12
end while
13
objReader.Close
14
fs.close
15
lblMessage.Text += "</pre>"
16
17
end sub
18
</script>
19
20
<html><body>
21
<form runat="server">
22
<asp:label id="lblMessage" runat=server />
23
</form>
24
</body></html>
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.
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
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
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
Ta statyczna metoda zwraca rozszerzenie pliku.
File.HasExtension
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
Typy wyliczeniowe określające uprawnienia i tryby otwierania
plików.
oraz
FileShare
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.
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
1
<%@ Page Language="VB" %>
2
<%@ Import Namespace="System.IO" %>
3
<%@ Import Namespace="System.IO.IsolatedStorage" %>
4
5
<script runat="server">
6
sub Page_Load(obj as object, e as eventargs)
7
dim stream as IsolatedStorageFileStream
8
dim writer as StreamWriter
9
dim data as string = "niebieski"
10
11
stream = new IsolatedStorageFileStream("colors.txt", _
12
FileMode.OpenOrCreate)
13
writer = new StreamWriter(stream)
14
writer.WriteLine(data)
15
writer.Close()
16
end sub
17
</script>
18
19
<html><body>
20
</body></html>
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.
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
1
<%@ Page Language="VB" %>
2
<%@ Import Namespace="System.IO" %>
3
<%@ Import Namespace="System.IO.IsolatedStorage" %>
4
5
<script runat="server">
6
sub Page_Load(obj as object, e as eventargs)
7
dim stream as new IsolatedStorageFileStream _
8
("colors.txt", FileMode.OpenOrCreate)
9
dim objReader as new StreamReader(stream)
10
11
while objReader.Peek() > -1
12
Response.Write(Server.HTMLEncode _
13
(objReader.ReadLine) & "<br>")
14
end while
15
objReader.Close
16
end sub
17
</script>
18
19
<html><body>
20
<asp:Label id="lblMessage" runat="server" />
21
</body></html>
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 listingó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
1
<%@ Page Language="VB" %>
2
<%@ Import Namespace="System.IO" %>
3
<%@ Import Namespace="System.IO.IsolatedStorage" %>
4
5
<script runat="server">
6
sub Page_Load(obj as object, e as eventargs)
7
dim i as Integer
8
dim objISOFile as IsolatedStorageFile = _
9
IsolatedStorageFile.GetUserStoreForDomain()
10
11
lblMessage.Text = "<b>Pliki:</b> "
12
dim intCount = Ubound(objISOFile.GetFileNames("*.*"))
13
for i = 0 to intCount
14
lblMessage.Text += objISOFile.GetFileNames _
15
("*.*")(i) & "<br>"
16
next
17
18
lblMessage.Text += "<b>Komponenty .NET: </b>" & _
19
objISOFile.AssemblyIdentity.ToString & "<br>"
20
lblMessage.Text += "<b>Domena: </b>" & _
21
objISOFile.DomainIdentity.ToString & "<br>"
22
lblMessage.Text += "<b>Aktualna wielko
ść
: </b>" & _
23
objISOFile.CurrentSize.ToString & "<br>"
24
lblMessage.Text += "<b>Maksymalna wielko
ść
: </b>" & _
25
objISOFile.MaximumSize.ToString & "<br>"
26
end sub
27
</script>
28
29
<html><body>
30
<asp:Label id="lblMessage" runat="server" />
31
</body></html>
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.
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.