Sign in Join
Wiki copytemporary

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

OldNewLine
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).*

Back to history