Delphi, cz. 14
Tym razem będzie trochę o tworzeniu plików.
Tworzenie plików
Jeżeli programowałeś wcześniej w Pascalu to z tym nie powinno być problemów. Wogule nie powinno być z tym problemów. Nie jest to takie trudne, a łatwo to zapamiętać. Po pierwsze tworzenie pliku. Oto przykład:
procedure TForm1.Button1Click(Sender: TObject);
var
TF : TextFile; // nowa zmienna
begin
AssignFile(TF, 'C:\plik.txt'); // skojarzenie pliku ze zmienna
Rewrite(TF); // stworzenie pliku
Writeln(TF, 'Pierwsza linie pliku tekstowego');
CloseFile(TF); // zamkniecie pliku
end;
Przeanalizujmy ten przykład: pod zmienną "TF" utworzona została nowa zmienna typu "TextFile" oznaczająca plik tekstowy. Później nastąpiło skojarzenie nazwy pliku ze zmienną ( AssignFile ), następnie utworzenie pliku ( Rewrite ). Kolejne polecenie to zapisanie do pliku linii ( polecenie Writeln ). Ostatnia linia to zamknięcie pliku. Trudne? Chyba nie. Teraz coś trudniejszego czyli zapisanie tablicy.
const
Imiona : array [0..3] of String =
('Adam', 'Aneta', 'Marta', 'Magda');
procedure TForm1.Button1Click(Sender: TObject);
var
TF : TextFile; // nowa zmienna
i : Integer;
begin
AssignFile(TF, 'C:\plik.txt'); // skojarzenie pliku ze zmienna
Rewrite(TF); // stworzenie pliku
for i := Low(Imiona) to High(Imiona) do
Writeln(TF, Imiona[i]);
CloseFile(TF); // zamkniecie pliku
end;
Jak widzisz najpierw zadeklarowana została stała symbolizująca tablice. Wypełniona ona została wartościami. Następnie w procedurze pierwsza część jest taka sama, ale później następuje pętla. Jeszcze jedna rzecz o której nie powiedziałem, a dotyczy tablic. Otóż funkcja "Low" zwraca najmniejszy parametr tablicy, a funkcja "High" największą wartość tablicy. Wykonywana zostaje pętla, która ma za zadanie zapisać wartości z tabeli. Na samym końcu plik jest zamykany.
Teraz odczyt takiego pliku:
procedure TForm1.Button2Click(Sender: TObject);
var
TF : TextFile;
I : Integer;
Tablica : array[0..2] of String;
begin
AssignFile(TF, 'C:\plik.txt');
Reset(TF);
while not Eof(TF) do
begin
For I:=Low(Tablica) to High(Tablica) do
begin
Readln(TF, tablica[i]);
Memo1.Lines.Add(Tablica[i]);
end;
end;
CloseFile(TF);
end;
W tym wypadku następuje tutaj odczytanie pliku tekstowego. Zauważ polecenie "Reset". Otwiera ono plik tekstowy. Następnie wykonanie pętli. Polecenie "Eof" odczytuje plik tekstowy dopóki nie napotka na koniec tego pliku. Następnie następuje przypisanie wartości tablicom i dodanie poszczególnych lini pliku do komponentu Memo.
Istnieje także możliwość dopisywania linii do pliku tekstowego. Wykonuje to linia Append:
var
TF : TextFile;
begin
AssignFile(TF, 'C:\plik.txt');
Append(TF);
Writeln(TF, 'Dopisana linia');
CloseFile(TF);
Jeżeli teraz otworzysz plik to zobaczysz o jedną linię więcej...
Wyszukiwanie plików
Wyszukiwanie plików nie jest tak trudne jak myślisz :) Za chwilę przedstawię program, który przeszukuje w wybranym katalogu wszystkie pliki o podanej przez Ciebie masce ( rozszerzeniu ).
1. Najpierw umieść na formularzu komponent "DirectoryListBox" na palecie "Win 3.1". Jest to komponent pokazujący strukturę katalogów. Nazwij go "DirList"
2. Umieść komponent "DriveComboBox" ( paleta: Wn 3.1 ). Nazwij go "Drive"; z listy właściwości "DirList" tegoż komponentu wybierz "DirList". Oznacza to, że te dwa komponentu zostają ze sobą "połączone" i będą ze sobą współdziałały.
3. Umieśc taże komponent "ImageList";
4. Na formie połóż komponent Button;
5. Połóz także komponent Edit i nazwij go "Maska";
6. Teraz najważniejszy komponent - "ListView" ( paleta: Win32 ). Nazwij go "ListView". O działaniu tego komponentu przekonasz się już wkrótce. Z listy właściwości "SmallImages" wybierz "ImageList1". Oznacza to, że na komponent "ListView" będzie wyświetlał ikonki z "ImageList'a". Zmień właściwość "ViewStyle" tego komponentu ( ListView ) na "vsReport". Teraz trzeba stworzyć kolumny do tego komponentu. Odnajdź właściwość "Columns" - otworzy się edytor kolumn. Pierwszy przycisk z lewej dodaje nową kolumnę. Zmień jej właściwość "Caption" na "Ścieżka", a "Width" na 360. Stwórz teraz nową kolumnę i zmień jej właściwość "Caption" na "Rozmiar". Szerokość ( Width ) ustaw na 100.
Na tym zakończyło się kładzenie komponentów :) Teraz kod :) Dodaj do sekcji "private" taki nagłówek:
procedure FindFiles(Dir: String; Mask: String);
Cóż tu dużo mówić. Procedura ta zawiera dwa parametry. Pierwszy z nich oznacza katalog, w którym pliki będą wyszukiwane. Drugi parametr to rozszerzenia plików do znalezienia. Uzupełnij w sekcji "Implementation" taki tekst:
procedure TForm1.FindFiles(Dir, Mask: String);
var
SR : TSearchRec; // rekord
List : TListItem; // pozycja w ListView
Found : Integer; // zmienna oznacza ilosc znalezionych plikow
I : WORD;
Icon : TIcon; // ikona
begin
I := 0;
ListView.Items.Clear; // wyczyszczenie komponentu
Icon := TIcon.Create; // stworzenie ikony
// wyciagniecie ikony
Icon.Handle := ExtractAssociatedIcon(hInstance, PChar(Dir + '\' + Mask), i);
ImageList1.InsertIcon(0, Icon); // wstawienie ikony do komponentu
Found := FindFirst(Dir + '\' + Mask, faAnyFile, SR ); // odnajdź pliki
while ( Found = 0 ) do // rob dopoki liczba zbalezionych plikow nie rowna sie zero
begin
List := ListView.Items.Add; // stworz nowa pozycje
List.Caption := Dir + '\' + SR.Name; // ustaw pozycje
List.SubItems.Add(IntToStr(SR.Size) + ' bajtów'); // dodaj rozmiar pliku
List.ImageIndex := 0; // ustaw ikone
Found := FindNext(SR); // kontynuuj przeszukiwanie
end;
FindClose(SR); // zkaoncz przeszukiwanie
Icon.Free; // zwolnij zmienna
end;
Zacznijmy od początku. Stworzona została nowa zmienna typu "TSearchRec". Jest to informacja o pliku. Rekord ten przedstawia się tak:
TSearchRec = record
Time: Integer; // czas utworzenia pliku
Size: Integer; // rozmiar pliku
Attr: Integer; // atrybuty ( plik ukryty, systemowy itp. )
Name: TFileName; // nazwa pliku
ExcludeAttr: Integer;
FindHandle: THandle; // uchwyt pliku
FindData: TWin32FindData; // szczegółowe informacje dotyczące pliku ( na razie niepotrzebne )
Następna zadeklarowana zmienna to nowa pozycja w komponencie "ListView". Zmiena ta musi być typu "TListItem". Kolejne zmienne to ilość znalezionych plików, później ikona typu "TIcon". Później wyczyszczenie komponentu, następnie następuje tworzenie zmiennej. Później do tej zmiennej przypisywana zostaje ikona szukanego pliku. Tak się akurat składa, że procedura "ExtractAssociatedIcon" 'wyciąga' ikonę z wybranego pliku. Pierwszym jej parametrem jest słowo "hInstance" oznaczające zasoby pliku. Później ścieżka pliku z którego ma być wyciągnięta ikona. Użyte tutaj zostało rzutowanie gdyż ta ścieżka musi być typu "PChar". Na ścieżkę pliku składają się dwie zmienne: nazwa szukanego pliku + back-slash + maska szukanego pliku. Do komponentu "ImageList" zostaje dodana ikona ze zmiennej "Icon". Dodanie ikony może nastąpić za pośrednictwem procedury "InsertIcon". Pierwszym jej parametrem jest pozycja do której ma być wstawiona pozycja, a drugim musi być zmienna typu "TIcon" przechowująca ikonę.
Ok, ikona z pierwszego szukanego pliku została wyciągnięta i dodana do komponentu "ImageList". Kolejna linia to znajdowanie pliku. Wszystko następuje za sprawą funkcji "FindFirst". Pierwszym jej parametrem musi być katalog, w którym znajdowane będą pliki. Kolejny to typ znajdowanego pliku. W tym wypadku jest to każdy plik ( faAnyFile ). Możliwe są do zastosowania:
faReadOnly pliki tylko do odczytu
faHidden ukryte
faSysFile systemowe
faDirectory katalogi
faArchive archiwa
faAnyFile dowolne
No i ostatni parametr to struktura typu "TSearchRec". Innymi słowy następuje przypisanie szukanego pliku do tej właśnie struktury.
Co dalej? Wykonywana zostaje pętla, która działać będzie dopóki liczba znalezionych plików nie będzie się równać 0 czyli, że więcej plików do odnalezienia w tym katalogu nie ma. W pętli tej tworzona zostaje nowa pozycja w komponencie "ListView". W tej pozycji następuje przypisanie pola "Caption". Pole to będzie się składać się z nazwy katalogu, back-slash'a i nazwy odnalezionego pliku ( SR.Name ). Druga kolumna, którą wcześniej utworzyliśmy zawierać będzie rozmiar pliku ( SR.Size ). Do nowo utworzonej pozycji trzeba jeszcze przypisać numer ikony. Numer ten to cyfra 0. Dlatego, że do komponentu "ImageList" dodaliśmy ikonę w miejscu 0. Ostatnia instrukcja tej pętli to polecenie "FindNext" oznaczające dalsze szukanie. No i na samym końcu następuje zakończenie wyszukiwania i zwolnienie zmiennej "Icon".
Być może dałoby się zrobić to łatwiej bez wykorzystywanie komponentu "ListView", ale... nie było by wtedy takiego efektu.
Uzupełnij jeszcze procedurę "OnDblClick" komponentu "ListView". Wykonywana ona będzie podczas podwójnego nacisnięcia na pozycje. Uruchamiała ona będzie wybrany plik:
procedure TForm1.ListViewDblClick(Sender: TObject);
begin
{ Procedura otwiera wybrany plik po dwukrotnym nacisnieciu w pozycje
na komponencie "ListView" }
ShellExecute(Handle, 'open', PCHar(ListView.Selected.Caption), nil, nil,
SW_SHOWNORMAL);
end;
Wymaga dodania do listy uses słowa "ShellAPI". Teraz uzupełnij procedurę "OnClick" komponentu "Button":
procedure TForm1.Button1Click(Sender: TObject);
begin
{ Wykonaj procedure na podst. maski ustawionej w komponencie
TEdit oraz katalogu z komponentu "DirectoryListBox" }
FindFiles(DirList.Directory, Maska.Text);
end;
Uruchamia ona napisaną wcześniej procedurę wyszukiwania plików. Jako pierwszy parametr podawany jest tu katalog wybrany w komponencie "DirList". Drugi parametr to maska, którą należy wpisać w komponencie "Maska". Możesz już uruchomić program i zaobserwować jego działanie. W polu "Maska" wpisz maskę oznaczoną np:
*.pas lub *.txt
Jeszcze raz oto cały kod programu:
(**************************************************************)
(* Programme searching files for Delphi 5 *)
(* Copyright (c) 2001 by Adam Boduch *)
(* Build: 25 lutego 2001 r. *)
(* Service for programmers: *)
(* http://www.programowanie.of.pl *)
(* E-mail: boduch@poland.com *)
(**************************************************************)
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ImgList, FileCtrl, ShellAPI;
type
TForm1 = class(TForm)
DirList: TDirectoryListBox;
Drive: TDriveComboBox;
ImageList1: TImageList;
ListView: TListView;
Button1: TButton;
Maska: TEdit;
procedure Button1Click(Sender: TObject);
procedure ListViewDblClick(Sender: TObject);
private
{ Procedura przeszukująca pliki }
procedure FindFiles(Dir: String; Mask: String);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FindFiles(Dir, Mask: String);
var
SR : TSearchRec; // rekord
List : TListItem; // pozycja w ListView
Found : Integer; // zmienna oznacza ilosc znalezionych plikow
I : WORD;
Icon : TIcon; // ikona
begin
I := 0;
ListView.Items.Clear; // wyczyszczenie komponentu
Icon := TIcon.Create; // stworzenie ikony
// wyciagniecie ikony
Icon.Handle := ExtractAssociatedIcon(hInstance, PChar(Dir + '\' + Mask), i);
ImageList1.InsertIcon(0, Icon); // wstawienie ikony do komponentu
Found := FindFirst(Dir + '\' + Mask, faAnyFile, SR ); // odnajdź pliki
while ( Found = 0 ) do // rob dopoki liczba zbalezionych plikow nie rowna sie zero
begin
List := ListView.Items.Add; // stworz nowa pozycje
List.Caption := Dir + '\' + SR.Name; // ustaw pozycje
List.SubItems.Add(IntToStr(SR.Size) + ' bajtów'); // dodaj rozmiar pliku
List.ImageIndex := 0; // ustaw ikone
Found := FindNext(SR); // kontynuuj przeszukiwanie
end;
FindClose(SR); // zkaoncz przeszukiwanie
Icon.Free; // zwolnij zmienna
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
{ Wykonaj procedure na podst. maski ustawionej w komponencie
TEdit oraz katalogu z komponentu "DirectoryListBox" }
FindFiles(DirList.Directory, Maska.Text);
end;
procedure TForm1.ListViewDblClick(Sender: TObject);
begin
{ Procedura otwiera wybrany plik po dwukrotnym nacisnieciu w pozycje
na komponencie "ListView" }
ShellExecute(Handle, 'open', PCHar(ListView.Selected.Caption), nil, nil,
SW_SHOWNORMAL);
end;
end.
Kopiowanie, przenoszenie itp.
Kopiowanie czy przenoszenie pojedynczych plików na prawdę nie jest czymś szczególnym - oto przykłady:
CopyFile('C:\gry.zip', 'C:\Windows\Pulpit\gry.zip', True);
Kopiuje plik z jednego miejsca na drugie. Ostatni parametr "mówi", czy plik ma być zamieniony jeżeli już istnieje plik o tej samej nazwie.
MoveFile('C:\gry.zip', 'C:\Windows\Pulpit\gry.zip');
Przenosi plik z jednego miejsca na drugie.
Takie zastosowanie jednak jest rzadko stosowane ze względu na to, że mogą być przenoszone tylko pojedyńcze pliki. W tym celu należy skorzystać z funkcji WinAPI oferowanych przez Microsoft.
Dodaj więc do listy uses słowo "ShellAPI". Teraz gdzieś w procedurze napisz:
procedure TForm1.Button1Click(Sender: TObject);
var
S : TSHFileOpStruct;
begin
S.Wnd := Handle;
S.wFunc := FO_COPY; // operacja - kopiowanie
S.pFrom := 'C:\gry'; // z jakiego katalogu?
S.pTo := 'C:\Windows\Pulpit\gry'; // do jakiego katalogu?
S.fFlags := FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION or FOF_SIMPLEPROGRESS;
S.fAnyOperationsAborted := True; // jest mozliwosc anulowania?
S.lpszProgressTitle := 'Trwa kopiowanie. Nie widzisz?'; // tekst
ShFileOperation(S); // wykonaj
end;
To już jest bardziej skomplikowane, ale daje większe możliwości. Zostaje zadeklarowna specyficzna zmienna, która jest rekordem. Tak więc nalezy ten rekord wypełnić. Pierwszy parametr to uchwyt okna. Kolejny to operacja do wykonania:
- FO_COPY - kopiuje pliki z "pForm" do "pTo";
- FO_DELETE - usuwa katalog lub plik oznaczony przez "pFrom" ( "pTo" jest ignorowane [ nie trzeba pisać ]);
- FO_MOVE - przenosi katalog lub plik;
- FO_RENAME - zmienia nazwę z "pFrom" do "pTo";
Kolejny parametr to nazwa katalogu lub pliku do skopiowania. Następny do lokalizacja do której ma być skopiowany katalog. Kolejny to flagi:
- FOF_ALLOWUNDO - możliwe jest cofnięcie operacji;
- FOF_FILESONLY - przenosi tylko pliki z folderu, a nie pliki z pod - folderu;
- FOF_NOCONFIRMATION - w razie konieczności nie jest wyświetlana informacja (" Tak na wszystkie" ) w przypadku istnienia pliku o tej samej nazwie;
- FOF_NOCONFIRMMKDIR - nie tworzy nowego folderu jeżeli operacja tego wymaga;
- FOF_SILENT - okno kopiowania nie zostanie wyświetlone;
- FOF_SIMPLEPROGRESS - wyświetla wybrany przez Ciebie tekst w polu "lpszProgressTitle", ale nie wyświetla kopiowanego pliku;
- FOF_RENAMEONCOLLISION - w przypadku istnienia pliku o tej samej nazwie zmieniana jest jego nazwa;
Kolejny parametr "mówi", czy operacja może być przerwana przez użytkownika ( True ), czy tez nie ( False ). Ostatni parametr umożliwia ustawienie tekstu, który będzie widniał w oknie kopiowania. Trzeba jednak wówczas zastosować flagę: FOF_SIMPLEPROGRESS.
To by było na tyle. W kolejnym rozdziale napiszemy instalator. Zapraszam również na stronę: www.programowanie.of.pl |