Podporu souborů v Delphi lze rozdělit do tří bodů:
type
TTextSoub = TextFile;
procedure
TwndHlavni.btnOPClick(Sender: TObject);
var
Soub:
TTextSoub;
Radka: String;
begin
AssignFile(Soub,
`data.txt`);
Reset(Soub);
while not Eof(Soub) do
begin
ReadLn(Soub, Radka);
memoSoubor.Lines.Add(Radka);
end;
CloseFile(Soub);
end;
Poznámky:
Možná jste z Pascalu zvyklí na výrazy Text (pro označení textového souboru), Assign (pro asociování fyzického souboru s proměnnou) či Close (pro uzavření souboru). Ty jsou v Delphi nahrazeny výrazy TextFile, AssignFile, resp. CloseFile. Důvodem je, že původní znění je v Delphi použito k jinému účelu (např. Text je vlastnost některých komponent, např. Memo či Edit). „Staré“ názvy v Delphi sice přesto zůstaly zachovány i s původním významem, je ale nutné uvozovat je kvalifikátorem modulu System. Například místo Assign(F) použijte System.Assign(F).
Využijete-li poznatků předchozí kapitoly, jistě sami snadno přijdete na to, jak provést ošetření chyb. V Delphi je nejefektivnějším způsobem použití mechanismu výjimek (podrobněji viz níže). V „původním“ Pascalu bylo ošetření chyb samozřejmě řešeno trochu jinak (všichni „pascaláci“ si jistě pamatují nezapomenutelné IOResult apod…
Chcete-li pracovat s jiným než textovým souborem, použijte konstrukci file of <typ>, např. file of Integer (soubor s celými čísly).
Metody LoadFromFile, resp. SaveToFile jsou dostupné např. pro třídy TStrings, TPicture, TBitmap, pro některé datové komponenty (TBlobField, TMemoField, TGraphicField), pro grafické formáty (TGraphic, TIcon, TMetaFile) nebo pro OLE zásobníky. Podobné metody jsou k dispozici také u objektů TMediaPlayer.
Poznámka pro pokročilé uživatele:
Jinou třídou týkající se souborů je TIniFile. Ta popisuje speciálně inicializační soubory Windows 3.1. Ve vyšších Windows aplikace zpravidla nahrazují INI soubory systémovými registry. Delphi obsahují i třídy určené pro takovou situaci – TRegistry, resp. TRegistryIniFile. Třídy TIniFile a TRegistryIniFile mají společného předka (TCustoIniFile), proto umožňují kromě jiného změnu přístupu (registry vs. INI soubory) s minimálními změnami kódu.
Modifikujeme nyní příklad uvedený výše, jen použijeme zmíněnou metodu LoadFromFile.
procedure TwndHlavni.btnOPClick(Sender: TObject);
begin
memoSoubor.Lines.LoadFromFile(`data.txt`);
end;
Myslím, že úspora je více než zřejmá:-). Nemusíme deklarovat žádné typy, definovat žádné proměnné, otvírat žádné soubory, asociovat žádné názvy.
Poznámka pro pokročilé uživatele:
Další zajímavou formou v Delphi je podpora souborových streamů, která vychází z abstraktní třídy TStream. Tato třída má tři následníky: TFileStream, THandleStream a TMemoryStream. Většina jejich metod se týká komponent a používají je zpravidla jejich tvůrci, ale některé jsou použitelné pro kohokoliv (např. ReadBuffer).
| Error Code | Význam |
| 2 | File not found |
| 3 | Invalid file name |
| 4 | Too many open files |
| 5 | Access denied |
| 100 | Disk read error – hlášeno, chcete-li číst za koncem souboru - EOF (End of File) |
| 101 | Disk write error – hlášeno, chcete-li zapisovat na zaplněný disk |
| 102 | File not assigned – hlášeno, chcete-li použít proměnnou typu Text nebo TextFile bez předchozího volání Assign() |
| 103 | File not open – hlášeno, chcete-li pracovat se souborem, jenž nebyl otevřen některou z funkcí Reset(), Rewrite(), Append() |
| 104 | File not open for input – hlášeno, chcete-li číst ze souboru otevřeného pro zápis |
| 105 | File not open for output – hlášeno, chcete-li zapisovat do souboru otevřeného pro čtení |
| 106 | Invalid numeric format – hlášeno, chcete-li číst nečíselnou hodnotu z textového souboru do číselné proměnné |
Standardní obsluha výjimek (implicitní handler Delphi) dokáže samozřejmě výjimku ošetřit, i když ji sami neodchytnete (viz díl 10), a vypíše MessageBox s odpovídající hláškou podle konkrétní hodnoty ErrorCode. „Nezná“ ovšem všechny hodnoty ErrorCode, a tak se může stát, že uživateli vypíše hlášku typu „I/O Error 103“. Pokud byste tedy chtěli například hlášku počeštit (což u českých programů výrazně doporučuji!), nebo ošetřit opravdu všechny chyby, odchytněte a ošetřete výjimku sami. Podívejte se na následující příklad, který demonstruje ošetření chybových stavů v souvislosti s načítáním obsahu souboru do Memo.
procedure TwndHlavni.btnOPClick(Sender: TObject);
var
Soub: TTextSoub;
Radka: String;
begin
AssignFile(Soub, `data.txt`);
try
Reset(Soub);
try
while not
Eof(Soub) do begin
ReadLn(Soub, Radka);
memoSoubor.Lines.Add(Radka);
end;
// while
finally
CloseFile(Soub);
end; // finally
except
on E:EInOutError do
case E.ErrorCode of
2: ShowMessage(`Soubor nenalezen!`);
103:
ShowMessage(`Soubor neotevřen!`);
else
ShowMessage(`Chyba při práci se souborem: ` +
E.Message);
end; // case
end; //
except
end; // procedure
Asi byste sami dokázali vysvětlit, že ve vnějším bloku try se pokusíme soubor otevřít, a nepodaří-li se to, ošetříme výjimku (oznámíme chybu) a končíme. Ve druhém vnořeném bloku try (vnitřnějším) se pokusíme soubor načíst do komponenty Memo. Je jisté, že v tuto chvíli je soubor správně otevřen, takže v každém případě soubor posléze zavřeme (sekce finally).
V tomto příkladu tedy máme ošetřeny chyby při otvírání souboru i při vlastním čtení. Pokud by ovšem např. ReadLn generovala při chybě výjimku EReadError, chyby čtení by ošetřeny nebyly (neboť odchytáváme jen EInOutError). To ona ovšem negeneruje:-).
Poznámky pro pokročilé uživatele:
S problematikou I/O chyb souvisí také výjimky EReadError, resp. EWriteError. První je generována, pokusí-li se aplikace načíst ze streamu větší počet bytů, než je možno. Může být také generována, nedokáže-li Delphi načíst vlastnost při vytváření formuláře (komponenta načítá zdroje – resource – nekorektně, příp. zdroje jsou chybné). Analogicky funguje EWriteError.
Představte si, že byste měli v aplikaci mnoho procedur a funkcí, které budou pracovat se souborem. Opisovat vždy tentýž kód spojený s obsluhou výjimek je jistě nepříjemné a nudné. Naštěstí je to také zbytečné, neboť lze použít událost OnException objektu TApplication, ve které napíšeme ošetřující kód „jednou provždy“. Jednoduchá ukázka, ve které se aplikace po vzniku každé neošetřené výjimky ukončí:
procedure TwndHlavni.FormCreate(Sender: TObject);
begin
Application.OnException := AppException;
end;
procedure
TwndHlavni.AppException(Sender: TObject; E: Exception);
begin
Application.ShowException(E); // ukaž chybovou zprávu
Application.Terminate; // ukonči
aplikaci
end;
| Funkce | Význam |
| FileExist(jmeno) | Vrací True, existuje-li zadaný soubor |
| DeleteFile(jmeno) | Smaže zadaný soubor a vrací True, podařilo-li se |
| RenameFile(stare, nove) | Přejmenuje soubor a vrací True, podařilo-li se |
| ChangeFileExt(jmeno, pripona) | Změní příponu souboru na zadanou a vrací nový název souboru |
| ExtractFileName(uplne_jmeno) | Extrahuje název souboru (tj. odstraní případnou cestu). Vrací získaný název. |
| ExtractFileExt(jmeno) | Vrací příponu daného souboru |
Poznámka: nekamenujte mě prosím za nesprávně (stručně) uváděnou syntaxi. Použil jsem ji pro úsporu místa, jistě si sami dokážete odvodit (příp. najít v helpu), že např. „úplný funkční prototyp“ funkce FileExists() vypadá takto:
function FileExists(const FileName: string): Boolean;
Poznámka pro pokročilé uživatele:
Dále existuje celá řada funkcí pracujících s adresáři a se jmény souborů v jednotce SysUtils.
K souborům lze v Delphi přistupovat též pomocí FileCreate(), FileOpen(), FileSeek(), FileWrite(), FileClose(). Tyto funkce tvoří "samostatnou" množinu funkcí pro práci se soubory za pomoci handlerů.