Grafikus C# – Windows Forms tanfolyam › 10.2 lecke

Windows Forms · 10.2 lecke · adatfolyamok

StreamReader, StreamWriter és using

A File.ReadAllText és társai egy lépésben olvasnak vagy írnak: kényelmesek, de a teljes fájlt a memóriába töltik, és nem adnak közbülső irányítást. Egy 2 GB-os naplófájl beolvasása így összeomlást okozhat, és a hosszú írás közben a program nem tud „élő” lenni. A megoldás az adatfolyam (stream): a fájlt részletenként olvasod vagy írod. Ebben a leckében a StreamReader és a StreamWriter használatát, a FileStream módjait (FileMode, FileAccess, FileShare), a using szerepét, a pufferelést és a Flush jelentőségét tanulod meg.

  • kb. 100 perc
  • közepes szint
  • adatfolyamok
Anime stílusú fiú és lány egy C# programozási feladatot beszél meg

A lecke végére

  • érted az adatfolyam fogalmát, és tudod, mikor jobb a StreamReader a ReadAllText-nél;
  • soronként olvasol (ReadLine ciklus, File.ReadLines), és kezeled a fájl végét;
  • írsz és fűzöl hozzá (StreamWriter, append), és érted a Flush és az AutoFlush szerepét;
  • a FileStream FileMode, FileAccess, FileShare értékeit választod;
  • mindig using blokkban dolgozol, és tudod, mi történik nélküle (zárolt fájl, elveszett adat);
  • nagy fájlt mutatsz be előrehaladással (Position / Length).

Mielőtt elkezded

Ehhez a leckéhez a 10.1 lecke (File, Path), a 9.8 lecke (Dispose, using) és a 4.7 lecke (kivételkezelés) szükséges.

10.1 File, Path, Directory →

StreamReader: olvasás soronként

Form1.cs (using System.IO;)C#
// klasszikus: ReadLine ciklus, a fájl végén null
int sorszam = 0;

using (StreamReader olvaso = new StreamReader(ut))
{
string sor;

while ((sor = olvaso.ReadLine()) != null)
{
sorszam++;

if (sor.Contains("HIBA")) { lstHibak.Items.Add(sorszam + ": " + sor); }
}
}

// egyszerűbb: File.ReadLines lusta felsorolás (egyszerre egy sor van a memóriában)
foreach (string sor2 in File.ReadLines(ut))
{
if (sor2.StartsWith("#")) { continue; } // megjegyzés kihagyása
}

// teljes tartalom (kicsi fájlnál)
using (StreamReader olvaso2 = new StreamReader(ut))
{
string mind = olvaso2.ReadToEnd();
}

// karakter szinten (feldolgozóknál, 10.5 lecke): Read() a következő karakter kódja, -1 a fájl vége
using (StreamReader olvaso3 = new StreamReader(ut))
{
int c;

while ((c = olvaso3.Read()) != -1)
{
char betu = (char)c;
}
}
AdatfolyamAz adatfolyam egy folyamatosan olvasható sorozat: nem tudod a végét előre, csak azt, hogy mikor érsz oda. A StreamReader a bájtokat szöveggé alakítja (kódolás, 10.3 lecke), és a ReadLine sorokat ad.
A fájl végeA ReadLine a fájl végén null értéket ad. Üres sor ("") nem a vége: az egy üres sor a fájlban. A while ((sor = ...) != null) a szokásos minta.
ReadLines vagy ReadAllLines?A ReadAllLines a teljes listát tömbbe tölti (memória), a ReadLines lusta: soronként ad, és megszakítható (break). Nagy fájlnál a ReadLines vagy a StreamReader.
MemóriaA ReadAllText a fájl méretének többszörösét foglalhatja (a szöveg UTF-16 kódolású a memóriában). 100 MB-os fájlnál ez több száz MB; GB-os fájlnál összeomlás.

Jósolj!

A fájlban 3 sor van, a második üres (alma, (üres), körte). A while ((sor = olvaso.ReadLine()) != null) ciklus hányszor fut le, és mi a sor értéke másodszorra?

Jóslat ellenőrzése

Háromszor; a másodiknál a sor értéke "" (üres szöveg, nem null). A ciklus csak a fájl végén áll meg, ahol a ReadLine null-t ad.

StreamWriter: írás és hozzáfűzés

Form1.csC#
// új fájl (vagy felülírás): append = false
using (StreamWriter iro = new StreamWriter(ut, false))
{
iro.WriteLine("Név;Pontszám");

foreach (Diak d in diakok)
{
iro.WriteLine(d.Nev + ";" + d.Pont);
}
} // itt záródik: a puffer kiíródik, a fájl felszabadul

// hozzáfűzés a meglévő végére: append = true
using (StreamWriter naplo = new StreamWriter(naploUt, true))
{
naplo.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " | " + uzenet);
}

// hosszú életű író (naplózó): egyszer megnyitva; az AutoFlush minden írás után a lemezre küld
private StreamWriter folyamatosNaplo;

private void NaploIndit()
{
folyamatosNaplo = new StreamWriter(naploUt, true) { AutoFlush = true };
}

private void Naploz(string uzenet)
{
folyamatosNaplo.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " | " + uzenet);
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (folyamatosNaplo != null) { folyamatosNaplo.Dispose(); } // a hosszú életű erőforrás felszabadítása (9.8 lecke)
}
Puffer és FlushA StreamWriter az adatot előbb pufferbe gyűjti, és egyszerre írja ki (gyorsabb). A Flush() azonnal kiírja a puffert. A Dispose (using vége) is meghívja. Ha a program összeomlik using és Flush nélkül, a pufferben lévő adat elveszik.
AutoFlushAz AutoFlush = true minden Write után kiírja a puffert: naplóknál hasznos (összeomlás után is megvan), de lassabb. Tömeges írásnál (több ezer sor) kapcsold ki.
appendA new StreamWriter(ut, false) felülír, a true hozzáfűz. Ez a WriteAllText és AppendAllText megfelelője (10.1 lecke).
Melyik megoldás?Ritka naplósornál az File.AppendAllText egyszerű (minden hívás megnyit és bezár). Sűrű naplózásnál (másodpercenként többször) a hosszú életű, nyitott StreamWriter hatékonyabb; ezt a FormClosed-ben zárd le.

Jósolj!

A kód StreamWriter iro = new StreamWriter(ut); iro.WriteLine("Fontos adat"); módon ír, using és Dispose nélkül, majd a program befejeződik. Mi van a fájlban?

Jóslat ellenőrzése

Gyakran üres fájl (vagy csak részleges tartalom): az adat a pufferben maradt, és sosem került a lemezre, mert nem volt Flush vagy Dispose. A fájl ráadásul zárolt maradhat, amíg a folyamat él. Mindig using.

FileStream: mód, hozzáférés és megosztás

A StreamReader/StreamWriter mögött egy FileStream áll: ez a fájl bájtjait olvassa/írja, és itt döntheted el, hogyan nyisd meg a fájlt. Három fogalom kell:

BeállításÉrtékekJelentés
FileModeOpen, OpenOrCreate, Create, CreateNew, Append, TruncateMi legyen, ha a fájl létezik / nem létezik? A Create felülír, a CreateNew hibát ad, ha már van, az Append a végére ír.
FileAccessRead, Write, ReadWriteMire használod a folyamot.
FileShareNone, Read, Write, ReadWriteMit engedsz másnak, amíg te használod (például olvashat-e közben más program).
Form1.csC#
// egy másik program által írt (nyitva tartott) naplófájl olvasása: engedd a másiknak az írást
using (FileStream fs = new FileStream(naploUt, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader olvaso = new StreamReader(fs))
{
txtNaplo.Text = olvaso.ReadToEnd();
}

// új fájl, amely nem írhat felül meglévőt
try
{
using (FileStream fs = new FileStream(ut, FileMode.CreateNew, FileAccess.Write, FileShare.None))
using (StreamWriter iro = new StreamWriter(fs))
{
iro.WriteLine("Új tartalom");
}
}
catch (IOException)
{
MessageBox.Show("Ez a fájl már létezik."); // a CreateNew nem ír felül
}
FileShare és zárolásA File.ReadAllText alapértelmezett megosztása FileShare.Read: ha egy másik program írásra nyitva tartja a fájlt, az olvasás IOException kivétellel hibázik. A FileShare.ReadWrite engedi a közös használatot.
FileMode.Create és TruncateA Create létrehozza vagy felülírja; a Truncate csak meglévő fájlt nyit meg, és kiüríti (hiba, ha nincs). A CreateNew biztonságos, ha nem akarsz véletlenül felülírni.
StreamReader a FileStream fölöttA new StreamReader(fs) a megnyitott folyamra épül. Mindkettő IDisposable: két egymásba fűzött using; a külső Dispose a belsőt is lezárja, de a kettős using a biztos.
Position és LengthA fs.Length a fájl mérete, a fs.Position a pillanatnyi hely bájtban: ebből számolható az előrehaladás (lásd lent).

Jósolj!

Egy másik program (például egy naplózó szolgáltatás) írásra nyitva tartja a naplo.txt fájlt. A te programod a File.ReadAllText("naplo.txt") hívást hajtja végre. Mi történik?

Jóslat ellenőrzése

Gyakran IOException (a fájlt másik folyamat használja): a ReadAllText nem engedi a közös írást. A FileStream FileShare.ReadWrite beállításával olvashatod a közben írt naplót.

Nagy fájlok: soronként és előrehaladással

Form1.csC#
// a keresés nagy fájlban: soronként, előrehaladással; az eredmények száma korlátozott
private int Keres(string ut, string szo, int maxTalalat)
{
int talalat = 0;
long sorszam = 0;

using (FileStream fs = new FileStream(ut, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader olvaso = new StreamReader(fs))
{
string sor;

while ((sor = olvaso.ReadLine()) != null)
{
sorszam++;

if (sor.IndexOf(szo, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
lstTalalat.Items.Add(sorszam + ": " + sor);
talalat++;

if (talalat >= maxTalalat) { break; } // a korlát megvéd a memória- és időtúllépéstől
}

if (sorszam % 5000 == 0)
{
pbHaladas.Value = (int)(fs.Position * 100 / Math.Max(1, fs.Length)); // az olvasott bájtok aránya
Application.DoEvents(); // vészmegoldás: a felület frissül (helyesen: háttérszál, 11. fejezet)
}
}
}

return talalat;
}
Korlát az eredményekreEgy gyakori szóra millió találat is lehet. A ListBox ezt nem bírja: legyen felső korlát (például 1000), és jelezd, ha elérted.
ElőrehaladásA fs.Position a már olvasott bájtok száma, a Length a teljes méret: a kettő hányadosa a készültség. A StreamReader pufferel, ezért a pozíció kissé előrébb jár, mint az utolsó feldolgozott sor: ez elfogadható.
A felület és a hosszú műveletA ciklus a felület szálán fut, ezért a program a keresés alatt „lefagy” (nem mozgatható az ablak). A Application.DoEvents() csak vészmegoldás (újrabelépési hibákat okozhat). A helyes megoldás a háttérszál és az async/await (11. fejezet).
BiztonságA fájl tetszőleges lehet (több GB-os, hibás kódolású). Védd korláttal és try–catch blokkal; a ReadToEnd és a ReadAllLines nagy fájlnál tilos.

Jósolj!

A ReadAllLines hívás egy 3 GB-os naplóra fut le egy 8 GB RAM-os gépen. Mi történik?

Jóslat ellenőrzése

A program OutOfMemoryException kivétellel leállhat (vagy a gép erősen lelassul): a szöveg a memóriában UTF-16 kódolású (a fájl kb. kétszerese), és a sorok külön objektumok. A File.ReadLines vagy a StreamReader egyszerre csak egy sort tart a memóriában.

📷 Képernyőkép helye

Mit tegyél ide: a naplózó és fájlnézegető: a találati lista, az előrehaladás-jelző és az állapotsor.Javasolt fájlnév: winforms-10-2-naplo.webp · Alt szöveg: A naplózó és nagyfájl-nézegető program

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. A fájl üres marad

StreamWriter iro = new StreamWriter(ut);
iro.WriteLine("adat"); // nincs Flush, nincs Dispose
Hiba és javítás

Az adat a pufferben maradt. Használj using blokkot, vagy hívj Flush és Dispose metódust.

2. A fájl nem törölhető a program használata után

Egy beolvasás után a File.Delete IOException kivételt ad.

Ok és javítás

A StreamReader nincs lezárva (using hiányzik), ezért a fájl zárolt. Használj using blokkot.

3. A hozzáfűzés felülírja a naplót

using (StreamWriter iro = new StreamWriter(naploUt))   // append nélkül
{
iro.WriteLine(uzenet);
}
Hiba és javítás

A második paraméter (append) alapértéke false: felülír. Hozzáfűzéshez new StreamWriter(naploUt, true).

4. Az első sor kimarad vagy duplán jön

string fejlec = olvaso.ReadLine();
while (olvaso.ReadLine() != null)
{
string sor = olvaso.ReadLine(); // a feltételben már elolvasta a sort!
}
Hiba és javítás

Kétszeri ReadLine hívás: a ciklusfeltétel elfogyasztja a sort. Használd a while ((sor = olvaso.ReadLine()) != null) mintát.

5. NullReferenceException az utolsó sornál

while (!olvaso.EndOfStream)
{
string sor = olvaso.ReadLine();
string[] m = sor.Split(';'); // a sor lehet null, ha valami közben megváltozott
}
Hiba és javítás

Az EndOfStream ellenőrzés és a ReadLine között a helyzet megváltozhat (főleg hálózati vagy írás alatt álló fájlnál). A while ((sor = ReadLine()) != null) minta biztonságosabb, mert a null ellenőrzés az olvasás részeként történik.

6. A program lefagy a hosszú beolvasás alatt

Nagy fájlnál az ablak nem reagál.

Ok és javítás

A ciklus a felület szálán fut. Átmeneti megoldás: DoEvents és korlát; a helyes: háttérszál és async (11. fejezet).

Mini projekt: naplózó és nagyfájl-nézegető

Készíts programot két résszel, amely az adatfolyamok használatát mutatja:

  1. Naplózó fül: txtUzenet + Naplóz gomb; a naplófájl az adatmappában (10.1 lecke AdatMappa()) naplo.txt; Egyszerű mód (File.AppendAllText) és Folyamatos mód (hosszú életű StreamWriter, AutoFlush) választható; btnTeszt: 10 000 sor beírása mindkét móddal, a Stopwatch időket kiírja.
  2. Naplónézegető: Megnyitás... (a FileShare.ReadWrite miatt akkor is megnyílik, ha a naplózó írja); a fájl utolsó 200 sora (a végéről olvasás: a FileStream.Seek vagy egyszerű: a teljes fájl végigolvasása egy 200 elemű körkörös sorral).
  3. Kereső: txtSzo + Keresés; a találatok (sorszám: sor) a listában, legfeljebb 1000; ProgressBar az előrehaladásról; Mégse jelző (a ciklus megszakadhat); az eredmény darabszáma és az eltelt idő az állapotsorban.
  4. Információ: a fájl mérete, a sorok száma (egy gyors számláló ciklus, a méretkorlát figyelmeztetéssel: ha > 200 MB, megerősítés kell), az első és utolsó sor.
  5. Hibatűrés: nem létező, zárolt, hozzáférés nélküli fájl, üres fájl, nagyon hosszú sor, bináris fájl; mindegyikre érthető üzenet; a program nem omlik össze.
  6. Erőforrások: minden olvasó és író using blokkban; a folyamatos író a FormClosed-ben lezárva.
  7. Teszteld: 10 000 soros napló mindkét móddal, a nézegető megnyitása írás közben, 100 MB-os fájlban a keresés (a felület fagyását jegyezd fel: a 11. fejezetben javítjuk), üres és nem létező fájl.
Megoldás megnyitása (próbáld ki előbb önállóan!)

Az utolsó 200 sor megtalálása egyszerű, memóriabarát módszerrel: Queue<string> korlátozott mérettel, a fájl végigolvasása közben.

Form1.cs (using System.IO; using System.Diagnostics; using System.Collections.Generic; using System.Linq;)C#
private StreamWriter folyamatos;
private string naploUt;
private bool megszakit = false;

private void Form1_Load(object sender, EventArgs e)
{
string mappa = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MiniNaplo");

Directory.CreateDirectory(mappa);
naploUt = Path.Combine(mappa, "naplo.txt");
}

private void Naploz(string uzenet)
{
string sor = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " | " + uzenet;

try
{
if (rbFolyamatos.Checked)
{
if (folyamatos == null) { folyamatos = new StreamWriter(new FileStream(naploUt, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) { AutoFlush = true }; }

folyamatos.WriteLine(sor);
}
else
{
File.AppendAllText(naploUt, sor + Environment.NewLine);
}
}
catch (IOException ex) { tsslUzenet.Text = "A naplózás nem sikerült: " + ex.Message; }
catch (UnauthorizedAccessException) { tsslUzenet.Text = "Nincs jogosultság a naplófájlhoz."; }
}

private void btnTeszt_Click(object sender, EventArgs e)
{
foreach (bool folyamat in new bool[] { false, true })
{
rbFolyamatos.Checked = folyamat;

Stopwatch ora = Stopwatch.StartNew();

for (int i = 0; i < 10000; i++) { Naploz("Teszt sor " + i); }

ora.Stop();
lstEredmeny.Items.Add((folyamat ? "Folyamatos" : "Egyszerű") + ": " + ora.ElapsedMilliseconds + " ms");
}
}

private void btnMegnyit_Click(object sender, EventArgs e)
{
Queue<string> utolso = new Queue<string>();
long db = 0;

try
{
using (FileStream fs = new FileStream(naploUt, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader olvaso = new StreamReader(fs))
{
string sor;

while ((sor = olvaso.ReadLine()) != null)
{
db++;
utolso.Enqueue(sor);

if (utolso.Count > 200) { utolso.Dequeue(); } // csak az utolsó 200 sor marad a memóriában
}
}

txtNezet.Lines = utolso.ToArray();
tsslUzenet.Text = db + " sor, a végén 200 látszik.";
}
catch (FileNotFoundException) { tsslUzenet.Text = "Még nincs naplófájl."; }
catch (IOException ex) { tsslUzenet.Text = "A fájl nem olvasható: " + ex.Message; }
}

private void btnKeres_Click(object sender, EventArgs e)
{
string szo = txtSzo.Text.Trim();

if (szo.Length == 0 || !File.Exists(naploUt)) { return; }

lstTalalat.Items.Clear();
megszakit = false;

Stopwatch ora = Stopwatch.StartNew();
int talalat = 0;
long sorszam = 0;

try
{
using (FileStream fs = new FileStream(naploUt, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader olvaso = new StreamReader(fs))
{
string sor;

while ((sor = olvaso.ReadLine()) != null && !megszakit)
{
sorszam++;

if (sor.IndexOf(szo, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
lstTalalat.Items.Add(sorszam + ": " + sor);

if (++talalat >= 1000) { tsslUzenet.Text = "Az első 1000 találat látszik."; break; }
}

if (sorszam % 5000 == 0)
{
pbHaladas.Value = (int)(fs.Position * 100 / Math.Max(1, fs.Length));
Application.DoEvents(); // vészmegoldás, 11. fejezet: háttérszál
}
}
}
}
catch (IOException ex) { tsslUzenet.Text = "A keresés nem sikerült: " + ex.Message; }

pbHaladas.Value = 100;
tsslUzenet.Text = talalat + " találat, " + sorszam + " sor, " + ora.ElapsedMilliseconds + " ms";
}

private void btnMegse_Click(object sender, EventArgs e) { megszakit = true; }

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (folyamatos != null) { folyamatos.Dispose(); }
}
📷 Képernyőkép helye

Mit tegyél ide: a kész program: a két mód mérési eredménye, a naplónézegető és egy keresés találatai.Javasolt fájlnév: winforms-10-2-kesz.webp · Alt szöveg: A kész naplózó és nézegető

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Sorok számlálása szavanként

Számold meg egy fájlban a szavak előfordulását (kis- és nagybetűtől függetlenül), és írd ki a 10 leggyakoribbat. Melyik adatszerkezet?

Egy lehetséges megoldás

Dictionary<string, int>: soronként bontod a szavakat (Split), és növeled a számlálót; a végén rendezel.

Form1.csC#
Dictionary<string, int> szamlalo = new Dictionary<string, int>();char[] elvalaszto = { ' ', ',', '.', ';', ':', '!', '?', '(', ')', '\t' };foreach (string sor in File.ReadLines(ut)){    foreach (string szo in sor.ToLowerInvariant().Split(elvalaszto, StringSplitOptions.RemoveEmptyEntries))    {        int db;        szamlalo.TryGetValue(szo, out db);        szamlalo[szo] = db + 1;    }}var top = szamlalo.OrderByDescending(p => p.Value).Take(10);

2. Fájl másolása adatfolyammal

Másolj egy nagy fájlt 80 KB-os darabokban, és mutass előrehaladást. Mit használsz?

Egy lehetséges megoldás

Két FileStream és egy bájttömb puffer: olvasás a forrásból, írás a célba, amíg a Read 0-t ad. A Stream.CopyTo egyszerű esetben elég, de nem ad előrehaladást.

Form1.csC#
byte[] puffer = new byte[81920];using (FileStream be = new FileStream(forras, FileMode.Open, FileAccess.Read))using (FileStream ki = new FileStream(cel, FileMode.CreateNew, FileAccess.Write)){    int olvasott;    while ((olvasott = be.Read(puffer, 0, puffer.Length)) > 0)    {        ki.Write(puffer, 0, olvasott);        pb.Value = (int)(be.Position * 100 / be.Length);    }}

3. Szűrés új fájlba

Egy naplóból csak a HIBA szót tartalmazó sorokat írd új fájlba. Hogyan kezeled egyszerre az olvasót és az írót?

Egy lehetséges megoldás

Két egymásba fűzött using: az egyik olvasó, a másik író; a ciklusban a feltételes WriteLine. Az egész fájl sosem kerül a memóriába.

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. Mit ad a ReadLine?

Mit ad a ReadLine a fájl végén, és mit egy üres sornál?

Megoldás megnyitása

A fájl végén null, üres sornál "" (üres szöveg).

2. Hozzáfűzés vagy felülírás?

Melyik kód fűz hozzá: (a) new StreamWriter(ut); (b) new StreamWriter(ut, true)?

Megoldás megnyitása

(b): a második paraméter az append. Az (a) felülír.

Közepes szint

3. Melyik FileMode?

Melyiket használod: (a) csak akkor hozzon létre fájlt, ha nincs; (b) meglévő fájl kiürítése; (c) végére írás?

Megoldás megnyitása

(a) CreateNew; (b) Truncate (vagy Create); (c) Append.

4. Az első sor kihagyása

Egy CSV első sora fejléc. Hogyan hagyod ki a ReadLines felsorolásban?

Megoldás megnyitása

A LINQ Skip(1): File.ReadLines(ut).Skip(1); ez lusta marad.

Kihívás szint

5. Farok (tail -f)

A program folyamatosan mutassa a naplófájl végére kerülő új sorokat. Mi a megoldás elve?

Megoldás megnyitása

A FileStream (FileShare.ReadWrite) pozícióját megjegyzed; egy időzítő (Timer) másodpercenként a megjegyzett pozícióról olvas, amíg van új tartalom (vagy FileSystemWatcher jelzésére). Ha a fájl rövidebb lett (rotáció), a pozíciót nullázod.

6. Naplóforgatás

A napló 1 MB felett új fájlba kerül (naplo.1.txt). Hogyan oldod meg biztonságosan?

Megoldás megnyitása

Írás előtt a FileInfo.Length ellenőrzése; ha elérte a korlátot, a folyamatos író lezárása, a régi fájl átnevezése (File.Move, a legrégebbi törlése), és új író nyitása. Az átnevezés hibája (zárolt fájl) nem állíthatja le a programot (10.9 lecke).

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Mikor jobb a StreamReader a ReadAllText-nél?

Nagy fájlnál, soronkénti feldolgozásnál, ha a memóriát és az idő-irányítást védeni kell.

2. Mi a puffer szerepe a StreamWriter-ben?

Az adatot gyűjti, és egyszerre írja ki (gyorsabb); a Flush és a Dispose üríti.

3. Mi történik using nélkül?

A puffer nem ürül (adatvesztés), és a fájl zárolt marad.

4. Mit jelent a FileShare?

Mit engedsz másnak, amíg a fájlt használod (olvasás, írás).

5. Hogyan számolsz előrehaladást?

fs.Position · 100 / fs.Length.

6. Mi a File.ReadLines előnye a ReadAllLines-szel szemben?

Lusta: egyszerre egy sort tart a memóriában, és megszakítható.

7. Mi a helyes minta a ReadLine ciklushoz?

while ((sor = olvaso.ReadLine()) != null).

Mit tudsz már?

  • Adatfolyammal olvasol és írsz (StreamReader, StreamWriter), soronként és hozzáfűzéssel.
  • Érted a pufferelést, a Flush és az AutoFlush szerepét.
  • A FileStream módjait (FileMode, FileShare) feladathoz választod.
  • Nagy fájlt kezelsz memóriabarát módon, előrehaladással.
  • Mindig using blokkban dolgozol.

Következő lecke: Szövegfájlok és UTF-8 kódolás

A bájtok és a karakterek viszonya: UTF-8, BOM, Windows-1250, az ékezetes betűk hibái és az átalakítás.