A InfoWiki wikiből
Text file
A program futása során sok adatot képes előállítani, illetve sok adatot kell bekérni, amelyekkel számolni tud. Nagyon gyakori az az eset, amikor az előállított adatokat kiírjuk diszkre valamilyen file-ba. Ennek oka, hogy ott tartósan (a gép kikapcsolása esetén) is megmaradnak ezek a részeredmények, illetve ez az egyik legegyszerűbb módja annak, hogy másik program felé az adatokat publikáljuk (egyik program kiírja, másik program beolvassa).
A legegyszerűbb felépítésű file az ún. text file szerkezet. Az ilyen file-ok sorokra tagoltak, és tartalmukat akár a legegyszerűbb windows-os Jegyzettömb (notepad) alkalmazással is megtekinthető, szerkeszthető.
A text file-ok sorokat (string) tartalmaznak. Minden sor végét speciális sorvége jel zárja, amely windows-ban a \r\n karakterek (13,10 kódú karakterek), Linux alatt a \n (10 kódú karakter) van használatban. Ez persze nem annyira lényeges információ, csak ha olyan alkalmazást akarunk írni, amely mindkét platformon futásképes kell legyen.
Text file írása
Az íráshoz a StreamWriter-t kell használni, megadván a létrehozandó file nevét:
string fname=@"c:\adatok.txt"; StreamWriter w = new StreamWriter(fname, false, Encoding.Default);
- az első paraméter (fname) adja meg a file nevét, amelybe írni szeretnénk.
- a második paraméter (false) azt adja meg, hogy amennyiben ilyen nevű file lenne már, akkor azt a rendszer törölje le, és üres állapotból induljon a fileba írás. Ha ide true-t adunk meg, akkor a már létező file tartalma megmarad, és amit most írunk bele majd a file-ba, az annak a végére fog íródni (hozzáfűzés, append).
- a harmadik paraméter a file-ba írás kódlapját adja meg. Az Encoding.Default a windows-unkban használt kódlap (alapértelmezett kódlap)
A fentiek után a file-ba írás máris indulhat. Az íráshoz a már ismerős WriteLine-t kell használni, csak nem a konzolra írunk (Console.WriteLine), hanem a file-ba szeretnénk írni, melyet most a w változónk azonosít. E miatt w.WriteLine-t kell megadnunk:
double r=23.4; w.WriteLine("Programozó=Hernyák Zoltán"); w.WriteLine("PI={0}",Math.PI); w.WriteLine("sugár={0}",r); w.WriteLine("Kerület={0}",2*r*Math.PI); ...
Ha minden adatot beleírtunk a file-ba, akkor a végén le kell azt zárnunk a Close() hívásával:
w.Close();
A teljes kód:
using System.IO; string fname=@"c:\adatok.txt"; StreamWriter w = new StreamWriter(fname, false, Encoding.Default); double r=23.4; w.WriteLine("Programozó=Hernyák Zoltán"); w.WriteLine("PI={0}",Math.PI); w.WriteLine("sugár={0}",r); w.WriteLine("Kerület={0}",2*r*Math.PI); w.Close();
Eredménye megtekinthető a jegyzettömb segítségével:
File-ból olvasás
A fileból olvasáshoz a StreamReader-t kell használni. A
string fname = @"c:\adatok.txt"; StreamReader r = new StreamReader(fname, Encoding.Default);
A megnyitás során meg kell adni
- a file nevét (fname)
- a file-ba íráskor használt kódlapot (ez most is a windows-unk alapértelmezett kódlapja lesz, Encoding.Default)
A file-ból olvasás során a ReadLine()-t kell használni, csak épp most nem a konzolról olvasunk (Console.ReadLine()), hanem a file-ból. A file-unkat most az r változó képviseli, ezért r.ReadLine()-al kell olvasni. A ReadLine most is string-et ad meg. Minden egyes olvasás során a file-unk egy-egy sorát kapjuk meg:
string s; s = r.ReadLine(); // "Programozó: Hernyák Zoltán" s = r.ReadLine(); // "PI=3,14159265358979" s = r.ReadLine(); // "sugár=23,4" s = r.ReadLine(); // "Kerület=147,026536188002"
Amikor befejezzük a file-ból olvasást, akkor a file-t le kell zárni a Close() segítségével:
r.Close();
A teljes kód:
using System.IO; string fname = @"c:\adatok.txt"; StreamReader r = new StreamReader(fname, Encoding.Default); string s; s = r.ReadLine(); // "Programozó: Hernyák Zoltán" s = r.ReadLine(); // "PI=3,14159265358979" s = r.ReadLine(); // "sugár=23,4" s = r.ReadLine(); // "Kerület=147,026536188002" r.Close();
Minden sor beolvasása
Amennyiben tudjuk előre, hogy a text file-unk 4 sorból áll, akár ciklust is szervezhetünk hozzá:
using System.IO; string fname = @"c:\adatok.txt"; StreamReader r = new StreamReader(fname, Encoding.Default); for (int i=0;i<4;i++) { string s = r.ReadLine(); ... } r.Close();
Ne rontsuk el: a file bezárását nem a ciklusban, hanem a cikluson kívül csak a legvégén kell megtenni!
Sokkal gyakoribb eset, amikor nem tudjuk előre, hogy a text file-unk hány sorból áll. Ekkor a fenti for ciklus nem használható, helyette while ciklust fogalmazunk. A feltételben azt kérdezzük le, hogy elértük-e már (end of file, end of stream) a text file végét.
using System.IO; string fname = @"c:\adatok.txt"; StreamReader r = new StreamReader(fname, Encoding.Default); while (!r.EndOfStream) { string s = r.ReadLine(); ... } r.Close();
Substring
Tegyük fel, hogy a beolvasó program szeretné tudni, mennyi volt a sugár értéke. Hogyan szedjük ki ezt az információt a text file-ból?
Ehhez tudnunk kell, hogy a keresett adat a sugár= sorban található, az egyenlőség jel jobb oldalán. Minden egyes sort beolvasunk, keresvén azt a sort, amelyiknek az eleje pontosan ez a karaktersorozat:
while (!r.EndOfStream) { string s = r.ReadLine(); if (s.StartsWith("sugár=")) Console.WriteLine(s); ... }
A StartsWith-el lehet a stringünk (sorunk) elejét megvizsgálni. A fenti if ki fogja keresni ezt a sort, és jelenleg ezt a sort kiírjuk a képernyőre.
De hogyan vegyük ki magát a számértéket a sorból? Le kell választani az s stringünkből ezt a darabkát a Substring() segítségével. Ennek meg kell adni:
- hanyadik betűtől akarjuk leválasztani
- hány betű hosszú darabot
Ezzel két gond is van: a hanyadik betű megadásakor ügyeljünk rá, hogy a betűk sorszámozása 0-tól kezdődik. A sugár=23,4 szövegünkben a 23,4 szakasz a 6 betűtől kezdődik, és 4 betű hosszú:
if (s.StartsWith("sugár=")) { string szam = s.Substring(6,4); // "23,4" double sugar = double.Parse(szam); Console.WriteLine("sugar beolvasas utan={0}",sugar); }
Split
Másik (és sokkal jobb módszer) a Split használata. A Split segítségével egy sztringet több felé vághatunk szét valamilyen elválasztó karakter mentén. A sugár=23,4 sort kettévághatjuk az = jel mentén két darabra, így különválik a bal oldali rész sugár és a jobb oldali rész 23,4. A kettévágás egy string[] tömböt eredményez. A tömbünk két elemű lesz, a 0 sorszámú elem az első darab, a 1 sorszámú elem pedig a második darabka lesz:
if (s.StartsWith("sugár=")) { string[] darabok = s.Split('='); // "23,4" double sugar = double.Parse(darabok[1]); Console.WriteLine("sugar beolvasas utan={0}",sugar); }
Miért jobb a Split mint a Substring? Ugyanis ha az értékünk nem 23,4, hanem mondjuk 123,345', amely már nem 4 karakter hosszú, akkor a fenti Substring máris nem jól működik. Van persze arra mód, hogy ezen segítsünk a string hosszából (s.Length) kiindulva, de a Split annyival egyszerűbben működik, hogy kár ezzel foglalkozni.