File Handling In Pascal/fi: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: File Handling In Pascal/fi
| Old | New | Line | |
|---|---|---|---|
| 1 | + | # Tiedostojen käsittely | |
| 2 | + | ||
| 3 | + | ## Yleistä | |
| 4 | + | ||
| 5 | + | Jokaisen ohjelmoijan tarvitsee tietää, miten käsitellään tiedostoja. Tiedostojen avulla säilytetään tietoja (dataa) eli tallennetaan tietoja niin, että ne voidaan hakea myöhemmin, ilman että niitä on luotava uudelleen. Tiedostojen avulla voidaan tallentaa käyttäjän asetukset, virhelokit, mittaus- tai laskentatulokset ja paljon muuta. Tämä sivu kertoo tiedostojen käsittelyn perusteet. | |
| 6 | + | ||
| 7 | + | ## Vanhempi aliohjelmallinen tapa | |
| 8 | + | ||
| 9 | + | Kun käytetään tiedostoja perinteisellä tavalla Pascalissa, voidaan käyttää TextFile tiedostotyyppiä (joka on yksinkertaisesti tekstiä sisältävä tiedosto: tekstitiedosto) tekstin tallentamiseen. Jokainen rivi päättyy rivin loppumerkkiin ( [[End of Line|LineEnding]] ). Tämän tyyppisen tiedostoon voidaan tallentaa merkkijonojen lisäksi myös numeroita, jotka on muotoiltu eri tavoin. Nämä tiedostot voidaan avata ja muokata Lazarus IDE:ssä tai jossain muussa tekstieditorissa. | |
| 10 | + | ||
| 11 | + | Tiettyjä tarkoituksia varten voidaan luoda oma tiedostotyyppi, joka voi tallentaa vain yhden tyyppistä dataa. Esimerkiksi: | |
| 12 | + | ||
| 13 | + | ``` pascal | |
| 14 | + | ... | |
| 15 | + | type | |
| 16 | + | TIntegerFile = file of integer; // Voidaan kirjoittaa vain kokonaislukuja tiedostoon | |
| 17 | + | TExtendedFile = file of extended; // Voidaan kirjoittaa vain reaalilukuja tiedostoon | |
| 18 | + | TCharFile = file of char; // Voidaan kirjoittaa vain yksittäisiä char-tyyppisiä merkkejä tiedostoon | |
| 19 | + | ``` | |
| 20 | + | ||
| 21 | + | ### I/O virheenkäsittely | |
| 22 | + | ||
| 23 | + | [I/O-virheenkäsittelyn lippu](http://www.freepascal.org/docs-html/prog/progsu38.html#x45-440001.2.38) kertoo kääntäjälle, miten käsitellä virheetilanteita: nostetaan poikkeus tai tallennetaan I/O- käsittelyn tulos IOResult-muuttujalle. I/O-virheenkäsittelyn lippu on ohje kääntäjälle. Se voidaan ottaa käyttöön tai poistaa se käytöstä: | |
| 24 | + | ||
| 25 | + | ``` pascal | |
| 26 | + | {$I+} // Virheet johtavat EInOutError-poikkeukseen (oletusarvo) | |
| 27 | + | {$I-} // Poista I/O-virheet: jolloin tarkistetaan virhekoodi IOResult-muuttujasta | |
| 28 | + | ``` | |
| 29 | + | ||
| 30 | + | I/O-virheiden ({\$ I-}) poistaminen vie tiedostotoimintojen tulokset IOResult-muuttujalle. Tämä on [[Cardinal|cardinal (numero) tyyppinen arvo]] . Eri numerot merkitsevät erilaisia virheitä. Joten kannattaa tarkistaa erilaisten virheiden dokumentaatiot [1](http://www.freepascal.org/docs-html/rtl/system/ioresult.html). | |
| 31 | + | ||
| 32 | + | ### Tiedostonkäsittelyn aliohjelmat | |
| 33 | + | ||
| 34 | + | Nämä tiedoston käsittelyn aliohjelmat ja funktiot sijaitsevat System-käännösyksikössä. Katso lisätietoja FPC: n dokumentaatiosta: [Reference for 'System' unit](http://www.freepascal.org/docs-html/rtl/system/index-5.html). | |
| 35 | + | ||
| 36 | + | - **AssignFile** - Anna tiedoston nimi | |
| 37 | + | - **Append** - Avaa olemassa olevan tiedoston tietojen lisäämiseksi tiedoston loppuun ja muokkaamalla sitä | |
| 38 | + | - **BlockRead** - Lukee dataa (typittömästä) tiedostosta muistiin | |
| 39 | + | - **BlockWrite** - Kirjoittaa dataa muistista (tyypittömään) tiedostoon | |
| 40 | + | - **CloseFile** - Sulkee avatun tiedoston | |
| 41 | + | - **EOF** - Tiedoston lopun tarkistus | |
| 42 | + | - **Erase** - Poistaa tiedoston levyltä | |
| 43 | + | - **FilePos** - Kertoo paikan tiedostossa | |
| 44 | + | - **FileSize** - Kertoo tiedoston koon | |
| 45 | + | - **Flush** - Tyhjentää tiedostopuskurin levylle. | |
| 46 | + | - **IOResult** - Palauttaa viimeisen tiedoston IO-toiminnon tuloksen | |
| 47 | + | - **Read** - Lukee tekstitiedostosta | |
| 48 | + | - **ReadLn** - Lukee tekstitiedostosta ja siirtyy seuraavaalle riville | |
| 49 | + | - **Reset** - Avaa tiedoston lukemista varten | |
| 50 | + | - **Rewrite** - Luo tiedoston kirjoittamista varten | |
| 51 | + | - **Seek** - Vaihtaa sijaintia tiedostossa | |
| 52 | + | - **SeekEOF** - Aseta sijainti tiedoston loppuun | |
| 53 | + | - **SeekEOLn** - Aseta sijainti rivin loppuun | |
| 54 | + | - **Truncate** - Leikkaa tiedosto vain sijaintiin asti | |
| 55 | + | - **[[Write]]** - Kirjoita muuttuja tiedostoon | |
| 56 | + | - **WriteLn** - Kirjoita muuttuja tekstitiedostoon ja siirry uudelle riville | |
| 57 | + | ||
| 58 | + | ### Esimerkki | |
| 59 | + | ||
| 60 | + | Täydellinen esimerkki TextFile-tyyppisen tekstitiedoston käsittelystä: | |
| 61 | + | ||
| 62 | + | ``` pascal | |
| 63 | + | program CreateFile; | |
| 64 | + | ||
| 65 | + | uses | |
| 66 | + | Sysutils; | |
| 67 | + | ||
| 68 | + | const | |
| 69 | + | C_FNAME = 'textfile.txt'; | |
| 70 | + | ||
| 71 | + | var | |
| 72 | + | tfOut: TextFile; | |
| 73 | + | ||
| 74 | + | begin | |
| 75 | + | // Asetetaan luotavalle tiedostolle nimi | |
| 76 | + | AssignFile(tfOut, C_FNAME); | |
| 77 | + | ||
| 78 | + | // Käytä poikkeuksia virheiden varalta (tämä on oletusarvo, joten sitä ei ehdottomasti vaadita) | |
| 79 | + | {$I+} | |
| 80 | + | ||
| 81 | + | // Tee tiedostojen luominen, try/except lohkossa käsittellään virheet | |
| 82 | + | try | |
| 83 | + | // Luo tiedosto, kirjoita jotain tekstiä siihen ja sulje se. | |
| 84 | + | rewrite(tfOut); | |
| 85 | + | ||
| 86 | + | writeln(tfOut, 'Hello textfile!'); | |
| 87 | + | writeln(tfOut, 'The answer to life, the universe and everything: ', 42); | |
| 88 | + | ||
| 89 | + | CloseFile(tfOut); | |
| 90 | + | ||
| 91 | + | except | |
| 92 | + | // Jos tapahtui virhe (/poikkeus) niin syy löytyy täältä | |
| 93 | + | on E: EInOutError do | |
| 94 | + | writeln('File handling error occurred. Details: ', E.ClassName, '/', E.Message); | |
| 95 | + | end; | |
| 96 | + | ||
| 97 | + | // Anna palautetta ja odota näppäimen painamista | |
| 98 | + | writeln('File ', C_FNAME, ' created if all went ok. Press Enter to stop.'); | |
| 99 | + | readln; | |
| 100 | + | end. | |
| 101 | + | ``` | |
| 102 | + | ||
| 103 | + | Nyt voidaan avata tiedosto millä tahansa tekstieditorilla ja nähdä yllä olevan tekstin kirjoitettuna siihen! Voidaan myös testata virheenkäsittelyä suorittamalla ohjelman kerran ja asettamalla tiedosto vain luettavaksi ja suorittamalla ohjelma uudelleen. | |
| 104 | + | ||
| 105 | + | Huomaa, että poikkeustoimintoa käytettiin, sillä se on helppo tapa toimia kun on useita tiedostoja ja käsitellä virheitä. Voidaan käyttää myös {\$ I-}, mutta silloin pitäisi tarkistaa IOResult jokaisen operaation jälkeen ja muokata seuraavaa operaatiota. | |
| 106 | + | ||
| 107 | + | Seuraavassa kerrotaan, kuinka tekstiä lisätään lisää tekstitiedostoon: | |
| 108 | + | ||
| 109 | + | ``` pascal | |
| 110 | + | program AppendToFile; | |
| 111 | + | ||
| 112 | + | uses | |
| 113 | + | Sysutils; | |
| 114 | + | ||
| 115 | + | const | |
| 116 | + | C_FNAME = 'textfile.txt'; | |
| 117 | + | ||
| 118 | + | var | |
| 119 | + | tfOut: TextFile; | |
| 120 | + | ||
| 121 | + | begin | |
| 122 | + | // Asetetaan tiedoston nimi, johon lisätään tekstiä | |
| 123 | + | AssignFile(tfOut, C_FNAME); | |
| 124 | + | ||
| 125 | + | // Embed the file handling in a try/except block to handle errors gracefully | |
| 126 | + | try | |
| 127 | + | // Open the file for appending, write some more text to it and close it. | |
| 128 | + | append(tfOut); | |
| 129 | + | ||
| 130 | + | writeln(tfOut, 'Hello again textfile!'); | |
| 131 | + | writeln(tfOut, 'The result of 6 * 7 = ', 6 * 7); | |
| 132 | + | ||
| 133 | + | CloseFile(tfOut); | |
| 134 | + | ||
| 135 | + | except | |
| 136 | + | on E: EInOutError do | |
| 137 | + | writeln('File handling error occurred. Details: ', E.Message); | |
| 138 | + | end; | |
| 139 | + | ||
| 140 | + | // Give feedback and wait for key press | |
| 141 | + | writeln('File ', C_FNAME, ' might have more text. Press enter to stop.'); | |
| 142 | + | readln; | |
| 143 | + | end. | |
| 144 | + | ``` | |
| 145 | + | ||
| 146 | + | Tekstiedoston lukeminen: | |
| 147 | + | ||
| 148 | + | ``` pascal | |
| 149 | + | program ReadFile; | |
| 150 | + | ||
| 151 | + | uses | |
| 152 | + | Sysutils; | |
| 153 | + | ||
| 154 | + | const | |
| 155 | + | C_FNAME = 'textfile.txt'; | |
| 156 | + | ||
| 157 | + | var | |
| 158 | + | tfIn: TextFile; | |
| 159 | + | s: string; | |
| 160 | + | ||
| 161 | + | begin | |
| 162 | + | // Give some feedback | |
| 163 | + | writeln('Reading the contents of file: ', C_FNAME); | |
| 164 | + | writeln('========================================='); | |
| 165 | + | ||
| 166 | + | // Set the name of the file that will be read | |
| 167 | + | AssignFile(tfIn, C_FNAME); | |
| 168 | + | ||
| 169 | + | // Embed the file handling in a try/except block to handle errors gracefully | |
| 170 | + | try | |
| 171 | + | // Open the file for reading | |
| 172 | + | reset(tfIn); | |
| 173 | + | ||
| 174 | + | // Keep reading lines until the end of the file is reached | |
| 175 | + | while not eof(tfIn) do | |
| 176 | + | begin | |
| 177 | + | readln(tfIn, s); | |
| 178 | + | writeln(s); | |
| 179 | + | end; | |
| 180 | + | ||
| 181 | + | // Done so close the file | |
| 182 | + | CloseFile(tfIn); | |
| 183 | + | ||
| 184 | + | except | |
| 185 | + | on E: EInOutError do | |
| 186 | + | writeln('File handling error occurred. Details: ', E.Message); | |
| 187 | + | end; | |
| 188 | + | ||
| 189 | + | // Wait for the user to end the program | |
| 190 | + | writeln('========================================='); | |
| 191 | + | writeln('File ', C_FNAME, ' was probably read. Press enter to stop.'); | |
| 192 | + | readln; | |
| 193 | + | end. | |
| 194 | + | ``` | |
| 195 | + | ||
| 196 | + | ## Olio tyyli | |
| 197 | + | ||
| 198 | + | Edellä mainittujen perinteisteisten tiedostojen käsittelyn rutiinien lisäksi on olemassa oliotyyli, joka käyttää tietovirtojen käsitettä (- dataa) korkeammalla abstraktiotasolla. Tämä tarkoittaa, että tiedot voidaan lukea tai kirjoittaa mihin tahansa paikkaan (levy, muisti, laitteisto-portit jne.) Yhdellä yhtenäisellä tavalla. | |
| 199 | + | ||
| 200 | + | Lisäksi useimmilla merkkijonojen käsittelyluokilla on mahdollisuus ladata ja tallentaa sisältöä tiedostoon. Näitä menetelmiä kutsutaan yleensä nimellä SaveToFile ja LoadFromFile. Monet muut oliot (kuten Lazarus grid:t) ovat samanlaisia toimintoja, kuten Lazaruksen datasets (DBExport). Kannattaa katsoa dokumentaatiota tai lähdekoodia ennen kuin yrittää tehdä omia tallennus- / latausrutiineita. | |
| 201 | + | ||
| 202 | + | ### Yleinen tapa kaikille tyypeille | |
| 203 | + | ||
| 204 | + | Tiedostojen avaamisessa voidaan käyttää TFileStream-luokkaa. Tähän luokkaan on kapseloitu aliohjelmat FileOpen, FileCreate, FileRead, FileWrite, FileSeek ja FileClose. Kyseinen luokka löytyy SysUtils käännösyksiköstä. | |
| 205 | + | ||
| 206 | + | [I/O-rutiineja](http://www.freepascal.org/docs-html/rtl/sysutils/ioroutines.html) | |
| 207 | + | ||
| 208 | + | Tässä on hyvin yksinkertainen esimerkki yhden tiedoston lisäämisestä toiseen tietovirtojen (stream) avulla. Se vastaa edellä mainittua lisäystä, mutta paljon yksinkertaisempaa: | |
| 209 | + | ||
| 210 | + | ``` pascal | |
| 211 | + | program inoutstream; | |
| 212 | + | uses | |
| 213 | + | classes,sysutils; | |
| 214 | + | var | |
| 215 | + | Instream,OutStream:TFilestream; | |
| 216 | + | begin | |
| 217 | + | if (ParamCount = 2) and | |
| 218 | + | FileExists(ParamStr(1)) and | |
| 219 | + | FileExists(ParamStr(2)) then | |
| 220 | + | begin | |
| 221 | + | instream := TFilestream.Create(ParamStr(1), fmOpenRead); | |
| 222 | + | try | |
| 223 | + | outstream :=TFilestream.Create(Paramstr(2), fmOpenwrite); | |
| 224 | + | try | |
| 225 | + | outstream.position := Outstream.size; | |
| 226 | + | outstream.copyfrom(instream,0);// appends | |
| 227 | + | finally | |
| 228 | + | instream.free; | |
| 229 | + | end; | |
| 230 | + | finally | |
| 231 | + | outstream.free; | |
| 232 | + | end; | |
| 233 | + | end else writeln('use: inoutstream <infile> <outfile>'); | |
| 234 | + | end. | |
| 235 | + | ``` | |
| 236 | + | ||
| 237 | + | Alla olevassa esimerkissä huomaa, kuinka tiedostojen käsittelytoiminta rajataan try ... except-lohkolla, jossaa virheet käsitellään oikein samalla tavoin kuin perinteisillä tiedostojen käsittelyrutiineilla (kuten ei sommitella esimerkkiä, jossa fsOut.writeä ei ole sijoitettu try ... finally lohkoon). | |
| 238 | + | ||
| 239 | + | ``` pascal | |
| 240 | + | program WriteBinaryData; | |
| 241 | + | {$mode objfpc} | |
| 242 | + | ||
| 243 | + | uses | |
| 244 | + | Classes, Sysutils; | |
| 245 | + | ||
| 246 | + | const | |
| 247 | + | C_FNAME = 'binarydata.bin'; | |
| 248 | + | ||
| 249 | + | var | |
| 250 | + | fsOut : TFileStream; | |
| 251 | + | ChrBuffer: array[0..2] of char; | |
| 252 | + | ||
| 253 | + | begin | |
| 254 | + | // Set up some random data that will get stored | |
| 255 | + | ChrBuffer[0] := 'A'; | |
| 256 | + | ChrBuffer[1] := 'B'; | |
| 257 | + | ChrBuffer[2] := 'C'; | |
| 258 | + | ||
| 259 | + | // Catch errors in case the file cannot be created | |
| 260 | + | try | |
| 261 | + | // Create the file stream instance, write to it and free it to prevent memory leaks | |
| 262 | + | fsOut := TFileStream.Create( C_FNAME, fmCreate); | |
| 263 | + | fsOut.Write(ChrBuffer, sizeof(ChrBuffer)); | |
| 264 | + | fsOut.Free; | |
| 265 | + | ||
| 266 | + | // Handle errors | |
| 267 | + | except | |
| 268 | + | on E:Exception do | |
| 269 | + | writeln('File ', C_FNAME, ' could not be created because: ', E.Message); | |
| 270 | + | end; | |
| 271 | + | ||
| 272 | + | // Give feedback and wait for key press | |
| 273 | + | writeln('File ', C_FNAME, ' created if all went ok. Press Enter to stop.'); | |
| 274 | + | readln; | |
| 275 | + | end. | |
| 276 | + | ``` | |
| 277 | + | ||
| 278 | + | Voidaan myös ladata koko tiedosto muistiin, jos sen koko on suhteellisesti pienempi kuin käytettävissä oleva järjestelmämuisti. Suuremmat koot saattavat toimia, mutta käyttöjärjestelmä alkaa käyttää sivutus / swap-tiedostoa, mikä tekee siitä hyödyttömän suorituskyvyn näkökulmasta. | |
| 279 | + | ||
| 280 | + | ``` pascal | |
| 281 | + | program ReadBinaryDataInMemoryForAppend; | |
| 282 | + | {$mode objfpc} | |
| 283 | + | ||
| 284 | + | uses | |
| 285 | + | Classes, Sysutils; | |
| 286 | + | ||
| 287 | + | const | |
| 288 | + | C_FNAME = 'binarydata.bin'; | |
| 289 | + | ||
| 290 | + | var | |
| 291 | + | msApp: TMemoryStream; | |
| 292 | + | ||
| 293 | + | begin | |
| 294 | + | // Set up the stream | |
| 295 | + | msApp := TMemoryStream.Create; | |
| 296 | + | ||
| 297 | + | // Catch errors in case the file cannot be read or written | |
| 298 | + | try | |
| 299 | + | // Read the data into memory | |
| 300 | + | msApp.LoadFromFile(C_FNAME); | |
| 301 | + | ||
| 302 | + | // Seek the end of the stream so data can be appended | |
| 303 | + | msApp.Seek(0, soEnd); | |
| 304 | + | ||
| 305 | + | // Write some arbitrary data to the memory stream | |
| 306 | + | msApp.WriteByte(68); | |
| 307 | + | msApp.WriteAnsiString('Some extra text'); | |
| 308 | + | msApp.WriteDWord(671202); | |
| 309 | + | ||
| 310 | + | // Store the data back on disk, overwriting the previous contents | |
| 311 | + | msApp.SaveToFile(C_FNAME); | |
| 312 | + | ||
| 313 | + | // Handle errors | |
| 314 | + | except | |
| 315 | + | on E:Exception do | |
| 316 | + | writeln('File ', C_FNAME, ' could not be read or written because: ', E.Message); | |
| 317 | + | end; | |
| 318 | + | ||
| 319 | + | // Clean up | |
| 320 | + | msApp.Free; | |
| 321 | + | ||
| 322 | + | // Give feedback and wait for key press | |
| 323 | + | writeln('File ', C_FNAME, ' was extended if all went ok. Press Enter to stop.'); | |
| 324 | + | readln; | |
| 325 | + | end. | |
| 326 | + | </synyaxhighlight> | |
| 327 | + | ||
| 328 | + | Jos on useampia Gb:n tiedostoja, kannattaa lukea esimerkiksi 4096 tavua puskuriin (kannattaa käyttää useita tiedostoklustereita tai lohkokokoja) ja tehdä jotain kunkin puskurin lukiessa tietoja. | |
| 329 | + | ||
| 330 | + | <syntaxhighlight lang=pascal> | |
| 331 | + | var | |
| 332 | + | TotalBytesRead, BytesRead : Int64; | |
| 333 | + | Buffer : array [0..4095] of byte; // or, array [0..4095] of char | |
| 334 | + | FileStream : TFileStream; | |
| 335 | + | ||
| 336 | + | try | |
| 337 | + | FileStream := TFileStream.Create; | |
| 338 | + | FileStream.Position := 0; // Ensure you are at the start of the file | |
| 339 | + | while TotalBytesRead <= FileStream.Size do // While the amount of data read is less than or equal to the size of the stream do | |
| 340 | + | begin | |
| 341 | + | BytesRead := FileStream.Read(Buffer,sizeof(Buffer)); // Read in 4096 of data | |
| 342 | + | inc(TotalBytesRead, BytesRead); // Increase TotalByteRead by the size of the buffer, i.e. 4096 bytes | |
| 343 | + | // Do something with Buffer data | |
| 344 | + | end; | |
| 345 | + | ``` | |
| 346 | + | ||
| 347 | + | ### Tiedoston kopiointi | |
| 348 | + | ||
| 349 | + | Edellä esitetyllä tavalla voidaan toteuttaa yksinkertaisen tiedoston kopiointi-toiminnon (FreePascal:n RTL ei ole sellaista, tosin Lazaruksen kirjastoissa on [[CopyFile|kopiotiedosto]] ) | |
| 350 | + | ||
| 351 | + | ``` pascal | |
| 352 | + | program FileCopyDemo; | |
| 353 | + | // Demonstration of FileCopy function | |
| 354 | + | ||
| 355 | + | {$mode objfpc} | |
| 356 | + | ||
| 357 | + | uses | |
| 358 | + | classes; | |
| 359 | + | ||
| 360 | + | const | |
| 361 | + | fSource = 'test.txt'; | |
| 362 | + | fTarget = 'test.bak'; | |
| 363 | + | ||
| 364 | + | function FileCopy(Source, Target: string): boolean; | |
| 365 | + | // Copies source to target; overwrites target. | |
| 366 | + | // Caches entire file content in memory. | |
| 367 | + | // Returns true if succeeded; false if failed. | |
| 368 | + | var | |
| 369 | + | MemBuffer: TMemoryStream; | |
| 370 | + | begin | |
| 371 | + | result := false; | |
| 372 | + | MemBuffer := TMemoryStream.Create; | |
| 373 | + | try | |
| 374 | + | MemBuffer.LoadFromFile(Source); | |
| 375 | + | MemBuffer.SaveToFile(Target); | |
| 376 | + | result := true | |
| 377 | + | except | |
| 378 | + | //swallow exception; function result is false by default | |
| 379 | + | end; | |
| 380 | + | // Clean up | |
| 381 | + | MemBuffer.Free | |
| 382 | + | end; | |
| 383 | + | ||
| 384 | + | begin | |
| 385 | + | If FileCopy(fSource, fTarget) | |
| 386 | + | then writeln('File ', fSource, ' copied to ', ftarget) | |
| 387 | + | else writeln('File ', fSource, ' not copied to ', ftarget); | |
| 388 | + | readln() | |
| 389 | + | end. | |
| 390 | + | ``` | |
| 391 | + | ||
| 392 | + | ### Tekstitiedostojen käsittely (TStringList) | |
| 393 | + | ||
| 394 | + | Yleensä tekstitiedostojen avulla voit käyttää TStringList-luokkaa kun ladataan koko tiedosto muistiin ja päästä helposti sen riveihin. Tietenkin voidaan myös kirjoittaa StringList takaisin tiedostoon: | |
| 395 | + | ||
| 396 | + | ``` pascal | |
| 397 | + | program StringListDemo; | |
| 398 | + | {$mode objfpc} | |
| 399 | + | ||
| 400 | + | uses | |
| 401 | + | Classes, SysUtils; | |
| 402 | + | ||
| 403 | + | const | |
| 404 | + | C_FNAME = 'textfile.txt'; | |
| 405 | + | ||
| 406 | + | var | |
| 407 | + | slInfo: TStringList; | |
| 408 | + | ||
| 409 | + | begin | |
| 410 | + | // Create an instance of the string list to handle the textfile | |
| 411 | + | slInfo := TStringList.Create; | |
| 412 | + | ||
| 413 | + | // Embed the file handling in a try/except block to handle errors gracefully | |
| 414 | + | try | |
| 415 | + | // Load the contents of the textfile completely in memory | |
| 416 | + | slInfo.LoadFromFile(C_FNAME); | |
| 417 | + | ||
| 418 | + | // Add some more contents | |
| 419 | + | slInfo.Add('An extra line appended to the text'); | |
| 420 | + | slInfo.Add('And another one.'); | |
| 421 | + | slInfo.Add('Let''s stop here.'); | |
| 422 | + | slInfo.Add('It is now ' + DateTimeToStr(now)); | |
| 423 | + | ||
| 424 | + | // And write the contents back to disk, replacing the original contents | |
| 425 | + | slInfo.SaveToFile(C_FNAME); | |
| 426 | + | ||
| 427 | + | except | |
| 428 | + | // If there was an error the reason can be found here | |
| 429 | + | on E: EInOutError do | |
| 430 | + | writeln('File handling error occurred. Reason: ', E.Message); | |
| 431 | + | end; | |
| 432 | + | ||
| 433 | + | // Clean up | |
| 434 | + | slInfo.Free; | |
| 435 | + | ||
| 436 | + | // Give feedback and wait for key press | |
| 437 | + | writeln('File ', C_FNAME, ' updated if all went ok. Press Enter to stop.'); | |
| 438 | + | readln; | |
| 439 | + | end. | |
| 440 | + | ``` | |
| 441 | + | ||
| 442 | + | ### Demo: Tallenna yksi merkkijono tiedostoon | |
| 443 | + | ||
| 444 | + | Jotta voidaan kirjoittaa yksi merkkijonon tietovirtaan (stream), kannattaa käyttää alla määritettyä menettelytapaa. Huomaa, että Free Pascalin stringit eli merkkijonot voivat olla erittäin pitkiä, ja tämä on myös hyödyllinen tapa kirjoittaa suuria tekstitiedostoja tiedostoon. | |
| 445 | + | ||
| 446 | + | ``` pascal | |
| 447 | + | program SaveStringToPathDemo; | |
| 448 | + | {$mode objfpc} | |
| 449 | + | ||
| 450 | + | uses | |
| 451 | + | Classes, sysutils; | |
| 452 | + | ||
| 453 | + | const | |
| 454 | + | C_FNAME = 'textstringtofile.txt'; | |
| 455 | + | ||
| 456 | + | // SaveStringToFile: funktio tallentaa merkkijonon tiedostoon. | |
| 457 | + | // Jos funktio palauttaa true arvon niin merkkijono kirjoitettiin ok. | |
| 458 | + | // Jos ei niin tapahtui jonkinlainen virhe. | |
| 459 | + | function SaveStringToFile(theString, filePath: AnsiString): boolean; | |
| 460 | + | var | |
| 461 | + | fsOut: TFileStream; | |
| 462 | + | begin | |
| 463 | + | // By default assume the writing will fail. | |
| 464 | + | result := false; | |
| 465 | + | ||
| 466 | + | // Write the given string to a file, catching potential errors in the process. | |
| 467 | + | try | |
| 468 | + | fsOut := TFileStream.Create(filePath, fmCreate); | |
| 469 | + | fsOut.Write(theString[1], length(theString)); | |
| 470 | + | fsOut.Free; | |
| 471 | + | ||
| 472 | + | // At his point it is known that the writing went ok. | |
| 473 | + | result := true | |
| 474 | + | ||
| 475 | + | except | |
| 476 | + | on E:Exception do | |
| 477 | + | writeln('String could not be written. Details: ', E.ClassName, ': ', E.Message); | |
| 478 | + | end | |
| 479 | + | end; | |
| 480 | + | ||
| 481 | + | // | |
| 482 | + | // Main program | |
| 483 | + | // | |
| 484 | + | begin | |
| 485 | + | // Try to save a simple textstring in a file and give feedback of sucess. | |
| 486 | + | if SaveStringToFile('>> this text gets stored <<', C_FNAME) then | |
| 487 | + | writeln('Text succesfully written to a file') | |
| 488 | + | else | |
| 489 | + | writeln('Writing text to a file failed.'); | |
| 490 | + | ||
| 491 | + | // Wait for the user to press Enter | |
| 492 | + | readln | |
| 493 | + | end. | |
| 494 | + | ``` | |
| 495 | + | ||
| 496 | + | ## Tiedoston käsittely ISO Moodissa | |
| 497 | + | ||
| 498 | + | ### Komentoriviparametrit | |
| 499 | + | ||
| 500 | + | Ensimmäinen vaihtoehto ulkoisten tiedostojen määrittämiseksi ISO-tilassa on komentoriviparametrien avulla niiden ulkoisen järjestyksen mukaan. Esimerkki: | |
| 501 | + | ||
| 502 | + | ``` pascal | |
| 503 | + | program isotest1 (file1, file2); | |
| 504 | + | var | |
| 505 | + | file1: text; | |
| 506 | + | file2: file of integer; | |
| 507 | + | begin | |
| 508 | + | reset(file1); | |
| 509 | + | readln(file1); | |
| 510 | + | rewrite(file2); | |
| 511 | + | write(file2, 5); | |
| 512 | + | end. | |
| 513 | + | ``` | |
| 514 | + | ||
| 515 | + | Ohjelma kootaan `fpc -Miso isotest1.pas` ja suoritetaan `./isotest1 externa1l.txt external2.dat` . tiedostot1 on määritetty external1.txt: lle ja file2: lle external2.dat: lle. Ilman komentoriviparametreja tiedostot liitetään stdin ja stdout. Niin kauan kuin vain yksi syöttötiedosto ja yksi lähtö, sama tehtävä voidaan saavuttaa tällä komennolla: `./isotest1 <externa1l.txt >external2.dat`. tiedosto1 pitää olla olemassa ennen suoritusta, tiedosto2 luodaan sen aikana. | |
| 516 | + | ||
| 517 | + | ### Läpinäkyvät tiedostonimet | |
| 518 | + | ||
| 519 | + | Toinen vaihtoehto on läpinäkyvät tiedostonimet, joka saavutetaan kääntäjän asetuksella -Sr. Esimerkki: | |
| 520 | + | ||
| 521 | + | ``` pascal | |
| 522 | + | program isotest2 (file1, file2); | |
| 523 | + | var | |
| 524 | + | file1: text; | |
| 525 | + | file2: text; | |
| 526 | + | begin | |
| 527 | + | reset(file1); | |
| 528 | + | readln(file1); | |
| 529 | + | rewrite(file2); | |
| 530 | + | write(file2, 5); | |
| 531 | + | end. | |
| 532 | + | ``` | |
| 533 | + | ||
| 534 | + | Jos ohjelma on käännetty `fpc -Miso -Sr isotest2.pas`ja suoritetaan ilman komentoriviparametreja, ulkoiset tiedostot FILE1.txt ja FILE2.txt luetaan ja kirjoitetaan. Huomaa sisäisten tiedostonimien muunnokset isoiksi kirjaimiksi. Tiedostoja, joilla on eri tiedostonimet, voidaan edelleen käyttää komentoriviparametrien avulla. | |
| 535 | + | ||
| 536 | + | ## Katso myös | |
| 537 | + | ||
| 538 | + | - [[CopyFile]] Lazaruksen funktio (käytettävissä myös komentorivillä), joka kopioi tiedostot | |
| 539 | + | - [[File]] | |
| 540 | + | - [[Howto Use TOpenDialog|Kuinka käytetään avaa-dialogia]] | |
| 541 | + | - [[Howto Use TSaveDialog|Kuinka käytetään tallenna-dialogia]] | |
| 542 | + | ||
| 543 | + | --- | |
| 544 | + | *From the Free Pascal wiki, page "File Handling In Pascal/fi", as it stood on 2020-02-14 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
