W poprzednim tygodniu poznaliśmy podstawowe operacje wejściowe oraz wyjściowe, jakie oferuje nam język obiektowy C# 2.0. Nauczyliśmy się już zapisywać dane do pliku oraz je czytać. Dzisiaj poszerzymy sobie jeszcze naszą wiedzę na w/w temat, ale de facto dzisiejszy artykuł będzie poświęcony głównie metodom i właściwościom umożliwiającym manipulację plików oraz katalogów.
Zanim przejdziemy do meritum przypomnijmy sobie poznane przez nas tydzień temu operacje. W tym celu napiszmy prosty programik:
using System;
using System.IO;
namespace CentrumXP_19
{
class MojaKlasa
{
FileStream
fsZapis, fsOdczyt;
void Zapis()
{
fsZapis = new FileStream("C://mojPlik.txt", FileMode.Create);
StreamWriter sw = new
StreamWriter(fsZapis);
Console.WriteLine("Podaj Twoj ulubiony kolor:");
sw.WriteLine(Console.ReadLine());
sw.Close();
Console.WriteLine("Dane zostały zapisane do pliku tekstowego!");
}
void Odczyt()
{
string odczyt;
fsOdczyt = new FileStream("C://mojPlik.txt", FileMode.Open);
StreamReader sr = new
StreamReader(fsOdczyt);
Console.WriteLine("Odczytujemy dane z pliku.");
while ((odczyt=
sr.ReadLine()) != null)
{
Console.WriteLine("Twój ulubiony kolor to: {0}.", odczyt);
}
Console.WriteLine("Koniec odczytu z pliku tekstowego.");
}
static void Main()
{
MojaKlasa
mk = new MojaKlasa();
mk.Zapis();
Console.WriteLine();
mk.Odczyt();
}
}
}
Powyższy przykład jest przypomnieniem wiedzy, jaką zdobyliśmy w poprzednim tygodniu. Zdefiniowaliśmy sobie bowiem dwie metody, które odpowiednio zapisują do pliku tekstowego dane wprowadzone przez użytkownika (plik ten jest tworzony na dysku C pod nazwą: mojPlik.txt) oraz odczytują je z tegoż pliku. Obie te metody są wywołane w odpowiedni sposób w głównej metodzie statycznej Main().
Po skompilowaniu i uruchomieniu powyższego przykładu otrzymamy na ekranie następujące wyniki:
Znamy już przeznaczenie potężnej klasy FileStream, a także obiektów typu StreamWriter oraz StreamReader. Potrafimy już tworzyć pliki tekstowe (modyfikować je) i odczytywać z nich wpisane wcześniej informacje. Do tej pory jednak przedstawiliśmy bardzo prosty sposób tworzenia plików. Teraz chcemy poszerzyć tę wiedzę, która będzie stricte powiązana z manipulacją właśnie plików oraz katalogów, o których jak na razie nic nie pisaliśmy.
Potrzebne klasy do manipulacji plików i katalogów znajdują się w przestrzeni nazw System.IO. Są to między innymi: klasa File, która reprezentuje plik na dysku oraz klasa Directory, która odpowiada za różnego rodzaju działania na katalogach.
Klasa Directory udostępnia statyczne metody do tworzenia, sprawdzania poprawności oraz przemieszczenia się katalogów. Poniższa tabela przedstawia najważniejsze metody statyczne klasy Directory:
Nazwa metody | Zastosowanie metody |
CreateDirectory() | Tworzy wszystkie katalogi i podkatalogi określone przez parametr path |
GetCreationTime() | Zwraca i ustawia czas tworzenia katalogu |
GetDirectories() | Pobiera określone katalogi |
GetLogicalDrives() | Zwraca nazwę napędu logicznego |
Move() | Przemieszcza katalog i jego zawartość do miejsca określonego przez path |
Powyższe metody są statyczne, a więc nie trzeba tworzyć egzemplarza ich klasy tylko je wywoływać bezpośrednio.
Obok klasy Directory, drugą potężną klasą do manipulacji katalogami jest klasa DirectoryInfo. Klasa ta zawiera jedynie metody egzemplarza (nie ma bowiem żadnych metod statycznych).Poniższa tabela przedstawia najczęściej używane przez programistów metody oraz właściwości klasy DirectoryInfo:
Metoda lub właściwość | Zastosowanie metody |
Attributes | Właściwość, która pobiera i ustawia atrybuty aktualnego pliku |
Exists | Właściwość, która zwraca true, jeśli dany katalog istnieje |
FullName | Właściwość, która zwraca pełną ścieżkę do katalogu |
Root | Zwraca fragment ścieżki reprezentujący główny katalog |
Create() | Metoda, która pozwala utworzyć nowy katalog |
CreateSubdirectory() | Pozwala utworzyć podkatalog w określonej ścieżce |
Delete() | Pozwala usunąć katalog/podkatalog |
GetDirectories() | Zwraca listę podkatalogów |
GetFiles() | Zwraca listę plików, które znajdują się w danym katalogu |
MoveTo() | Pozwala przenieść katalog/podkatalog do odpowiedniego miejsca |
Zastosujmy więc niektóre metody i właściwości z powyższej tabeli w następującym przykładzie:
using System;
using System.IO;
namespace CentrumXP_19
{
class MojaKlasa
{
// definiujemy
zmienna poziom i ustawiamy ja na -1
int poziom = -1;
public static void Main(string[]
args)
{
MojaKlasa
mk = new MojaKlasa();
//wybieramy
poczatkowy podkatalog
string
mojaSciezka = "C:\\KatalogGlowny";
// definiujemy
obiekt typu DirectoryInfo
DirectoryInfo di = new DirectoryInfo(mojaSciezka);
//wywolanie
metody PrzegladKatalogow
mk.PrzegladKatalogow(di);
}
//metoda, ktora
wysietla informacje dotyczace odpowiedniego katalogu
public void
PrzegladKatalogow(DirectoryInfo dir)
{
//pierwszym
poziomem bedzie 0
poziom++;
// wyswietlamy
wszystkie katalogi i podkatalogi z okreslonej sciezki
Console.WriteLine("Poziom: {0}, nazwa: {1}", poziom,
dir.Name);
// wrzucamy do
tablicy wszystkie katalogi aktualnego folderu
DirectoryInfo[]
directories = dir.GetDirectories();
//przechodzimy
foreachem po wszystkich katalogach jakie aktualnie znajduja sie w tablicy
foreach (DirectoryInfo di in
directories)
{
//rekurencyjne
wywolanie metody PrzegladKatalogow()
PrzegladKatalogow(di);
}
// zmniejszamy
poziom
poziom--;
}
}
}
Powyższy programik to rekurencyjne zagłębianie się w podkatalogi. Na początku określamy katalog, dla którego będziemy wyświetlać wszystkie podkatalogi, jakie on posiada (w naszym przypadku będzie to KatalogGlowny, leżący na dysku C, który będzie miał 3 katalogi, z których jeden będzie miał jeszcze jeden własny podkatalog). Następnie dla tego głównego katalogu definiujemy obiekt di typu DirectoryInfo, po czym wywołujemy na nim metodę PrzegladKatalogow(), przekazując do niej utworzony wcześniej obiekt di. Zadaniem tej metody jest wyświetlenie wszystkich katalogów, jakie posiada KatalogGlowny, a następnie pobranie dla nich wszystkich ich podkatalogów. Liczba wszystkich podkatalogów aktualnego katalogu jest wyświetlana za pomocą metody GetDirectories(), która zwraca tablicę obiektów typu DirectoryInfo.
W instrukcji foreach „przechodzimy” po wszystkich podkatalogach aktualnego katalogu i..wywołujemy na nowo metodę PrzegladKatalogow() przekazując jej odpowiedni, aktualny podkatalog. Taki mechanizm nazywamy rekurencją. Innymi słowy, takie podejście powoduje rekurencyjne zagłębianie się metody w każdy podkatalog, a następnie przejście do następnego podkatalogu z tego samego poziomu.
Po skompilowaniu i uruchomieniu powyższego przykładu otrzymamy następujące wyniki:
Potrafimy już używać obiektów DirectoryInfo, a więc czas na poznianie drugiej ogromnej klasy, jaką jest niewątpliwie klasa File oraz jej imienniczka FileInfo. Podobnie jak w przypadku Directory i DirectoryInfo, tak i tutaj klasa File udostępnia statyczne metody do tworzenia, sprawdzania poprawności oraz przemieszczenia się plików, natomiast klasa FileInfo zawiera odpowiednie metody egzemplarza.
Poniższa tabela zawiera wybrane, publiczne metody statyczne klasy File:
Nazwa metody | Zastosowanie metody |
Copy() | Metoda do kopiowania istniejącego pliku do nowego pliku |
Create() | Tworzy nowy plik w miejscu, które określiliśmy w parametrze path |
Delete() | Usuwamy określony plik |
Exists | Właściwość, która zwraca true, jeśli dany plik istnieje |
GetCreationTime() | Metoda do pobierania daty utworzenia danego pliku |
Natomiast poniższa tabela prezentuje wybrane metody klasy FileInfo:
Metoda lub właściwość | Zastosowanie metody |
Attributes | Właściwość, która pobiera i ustawia atrybuty aktualnego pliku |
Exists | Właściwość, która zwraca true, jeśli dany plik istnieje |
FullName | Właściwość, która zwraca pełną ścieżkę do pliku |
LastWriteTime | Pobiera lub ustawia czas ostatniego dostępu |
Lenght | Zwraca rozmiar danego pliku |
Name | Zwraca nazwę danego pliku |
Create() | Tworzy nowy plik |
Delete() | Usuwa dany plik |
Open() | Otwiera dany plik z różnymi opcjami odczytu, zapisu etc. |
Wykorzystajmy teraz kilka metod oraz właściwości z powyższej tabeli i napiszmy program, który oprócz wyświetlania wszsytkich katalogów (podkatalogów) będzie również zwracał listę plików, jakie znajdują się w odpowiednich katalogach i podkatalogach:
using System;
using System.IO;
namespace CentrumXP_19
{
class MojaKlasa
{
// definiujemy
zmienna poziom i ustawiamy ja na -1
int poziom = -1;
public static void Main(string[]
args)
{
MojaKlasa
mk = new MojaKlasa();
//wybieramy
poczatkowy podkatalog
string
mojaSciezka = "C:\\KatalogGlowny";
// definiujemy
obiekt typu DirectoryInfo
DirectoryInfo di = new DirectoryInfo(mojaSciezka);
//wywolanie
metody PrzegladKatalogow
mk.PrzegladKatalogow(di);
}
//metoda, ktora
wysietla informacje dotyczace odpowiedniego katalogu
public void
PrzegladKatalogow(DirectoryInfo dir)
{
// pierwszym
poziomem bedzie 0
poziom++;
// wyswietlamy
wszystkie katalogi i podkatalogi z okreslonej sciezki
Console.WriteLine("Poziom: {0}, nazwa katalogu: {1}",
poziom, dir.Name);
// pobieramy
wszsytkie pliki, jakie znajduja sie w danym aktualnym katalogu
FileInfo[]
fi = dir.GetFiles();
//przechodzimy
foreachem po wszsytkich plikach jakie znajduja sie w danym aktualnym katalogu
foreach (FileInfo plik in fi)
{
Console.WriteLine("Poziom:
{0}, nazwa pliku: {1}, rozmiar: {2}, czas ostatniej modyfikacji: {3}",
poziom, plik.Name, plik.Length, plik.LastWriteTime);
}
// wrzucamy do
tablicy wszystkie katalogi aktualnego folderu
DirectoryInfo[]
directories = dir.GetDirectories();
//przechodzimy
foreachem po wszystkich katalogach jakie aktualnie znajduja sie w tablicy
foreach (DirectoryInfo di in
directories)
{
//rekurencyjne
wywolanie metody PrzegladKatalogow()
PrzegladKatalogow(di);
}
// zmniejszamy
poziom
poziom--;
}
}
}
Powyższy przykład wyświetla nie tylko listę wszystkich katalogów oraz podkatalogów z określonej ścieżki, ale również listę wszystkich plików, jakie znajdują się w tych folderach. W tym celu zdefiniowaliśmy sobie tablicę przechowującą obiekty FileInfo (listę plików) aktualnego katalogu (podkatalogu), a następnie za pomocą instrukcji foreach przechodzimy po wszystkich tych plikach i wyświetlamy odpowiednie na ich temat informacje.
Po uruchomieniu powyższego przykładu otrzymamy następujące wyniki:
Na koniec napiszemy program, który będzie podsumowaniem wiedzy, jaką zdobyliśmy dzisiaj oraz tydzień temu. Nasz program będzie tworzył na dysku C:\ naszego komputera folder a w nim plik, w którym będzie można napisać komentarz na temat portalu CentrumXP. Następnie z pliku tego będziemy odczytywać wpisany tekst i wyświetlać na ekranie komputera:
using System;
using System.IO;
namespace CentrumXP_19
{
class
MojaKlasa
{
static void Main(string[] args)
{
//tworzymy
katalog wraz z plikiem
MojaKlasa
mk = new MojaKlasa();
Console.WriteLine(@"Podaj nazwę folderu jaki chcesz stworzyć na dysku
C:\");
string nazwaFolderu = Console.ReadLine();
mk.NowyFolder(@"C:\" + nazwaFolderu);
Console.WriteLine("Stworzono folder: {0}", nazwaFolderu);
Console.WriteLine(@"Podaj nazwę pliku jaki chcesz stworzyć w folderze:
{0}:", nazwaFolderu);
string nazwaPliku = Console.ReadLine();
FileStream fs = new FileStream(@"C:\" + nazwaFolderu + @"\" + nazwaPliku, FileMode.Create);
//wpisujemy do
pliku tekst
Console.WriteLine("Napisz swój komentarz na temat portalu
CentrumXP:");
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(Console.ReadLine());
sw.Close();
Console.WriteLine("Twój komentarz został zapisany do pliku: {0}",
nazwaPliku);
//uruchamiamy
metode, ktora odczyta z pliku wpisany komentarz
DirectoryInfo di = new DirectoryInfo(@"C:\" + nazwaFolderu);
mk.MojaMetoda(di);
}
void NowyFolder(string
sciezka)
{
DirectoryInfo di = new
DirectoryInfo(sciezka);
di.Create();
}
void MojaMetoda(DirectoryInfo
dirInfo)
{
string mojeDaneOdczyt = string.Empty;
FileInfo[] fileInfo = dirInfo.GetFiles();
foreach (FileInfo fi in fileInfo)
{
FileStream fs = new FileStream(fi.FullName, FileMode.Open);
StreamReader sr = new
StreamReader(fs);
Console.WriteLine("Odczytujemy Twój komentarz.");
Console.WriteLine("Twój komentarz to:");
while
((mojeDaneOdczyt = sr.ReadLine()) != null)
{
Console.WriteLine(mojeDaneOdczyt);
}
sr.Close();
}
}
}
}
Powyższy przykład jest podsumowaniem poznanych przez nas dotychczas metod oraz właściwości, jakie najczęściej używane są przez programistę w czasie wykonywania różnorakich operacji wejścia – wyjścia. Mamy nadzieję, że przedstawione przez nas podstawy na w/w temat przyczynią się do rozpoczęcia ich używania w naszych programach oraz sprawią, że nie będą dla nas obce nawet w trudniejszych przykładach.
Po uruchomieniu programu otrzymamy następujący przykładowy ekran:
Za tydzień opowiemy sobie o atrybutach oraz mechaniźmie refleksji w języku obiektowym C# 2.0.