Grafikus C# – Windows Forms tanfolyam › 10.1 lecke Windows Forms · 10.1 lecke · fájlrendszer A programok adatai csak addig élnek, amíg a program fut: a tartós tároláshoz a fájlrendszerrel kell dolgozni. Eddig a fájlokat a párbeszédablakokon át, néhány File, Path és Directory
File metódussal kezelted (2.2, 7.8, 8.9 lecke). A 10. fejezet ezt rendszerbe foglalja. Az első lecke a fájlrendszer három alaposzlopa: a File és a FileInfo (fájlok), a Directory és a DirectoryInfo (mappák) és a Path (útvonalak összeállítása és bontása). Megtanulod a biztonságos útvonalépítést, az érvénytelen fájlnevek kezelését, a mappák bejárását és törlését, és a relatív útvonalak csapdáit.
A lecke végére
- a
Filestatikus metódusait használod (létezés, olvasás, írás, másolás, áthelyezés, törlés); - megkülönbözteted a
Fileés aFileInfoosztályt, és lekérdezed a fájl adatait; - útvonalat építesz és bontasz a
Pathosztállyal (Combine,GetFileName,GetExtension…), kézi összefűzés nélkül; - érvénytelen karaktereket tartalmazó fájlnevet tisztítasz meg;
- mappát hozol létre, listázol és törölsz (
Directory,EnumerateFiles); - érted a relatív útvonalak működését, és tudod, hová írhat a program;
- kezeled a tipikus kivételeket (
UnauthorizedAccessException,DirectoryNotFoundException).
Mielőtt elkezded
Ehhez a leckéhez a 7.4 és 7.8 lecke (MessageBox, fájlválasztók), a 4.7 lecke (try–catch alapjai) és az 5.6 lecke (az alkalmazás életciklusa) szükséges.
File és FileInfo
A File statikus osztály: minden metódusa útvonalat kap. Egyszerű, egyszeri műveletekre (olvas, ír, másol) ez a legkényelmesebb. A FileInfo egy konkrét fájlt reprezentáló objektum, amelynek tulajdonságai (méret, dátum) és metódusai vannak; többszöri használatnál hatékonyabb:
string ut = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "jegyzet.txt");
// létezés, írás, olvasás
if (!File.Exists(ut))
{
File.WriteAllText(ut, "Első sor" + Environment.NewLine); // létrehozza, vagy felülírja
}
File.AppendAllText(ut, "Újabb sor" + Environment.NewLine); // a végére fűz
string mind = File.ReadAllText(ut);
string[] sorok = File.ReadAllLines(ut);
// másolás, áthelyezés (átnevezés is), törlés
File.Copy(ut, ut + ".bak", true); // a true: felülírhatja a célt (különben IOException)
File.Move(ut + ".bak", ut + ".reg"); // a cél nem létezhet (különben IOException)
File.Delete(ut + ".reg"); // nem létező fájlnál nem dob hibát
// FileInfo: a fájl adatai
FileInfo info = new FileInfo(ut);
if (info.Exists)
{
lblInfo.Text = info.Name + " – " + info.Length + " bájt, módosítva: " + info.LastWriteTime.ToString("yyyy. MM. dd. HH:mm")
+ ", kiterjesztés: " + info.Extension + ", írásvédett: " + info.IsReadOnly;
}File egyszerűbb. Ha több adatot kérdezel le ugyanarról a fájlról (méret, dátum, név), a FileInfo kényelmesebb. A FileInfo adatai a létrehozás pillanatában gyorsítótárazódnak: frissítéshez Refresh() kell.WriteAllText a meglévő fájlt felülírja, figyelmeztetés nélkül. A Copy(forrás, cél, true) is. Felhasználói adatnál előbb kérdezz (7.4 lecke), vagy az OverwritePrompt segít (7.8 lecke).Move a fájlt átnevezi. A cél nem létezhet. Más meghajtóra másolás + törlés történik (lassabb).CreationTime, LastWriteTime, LastAccessTime helyi idő; az …Utc változatok egyetemes idő. A LastWriteTime a „mikor módosult” kérdésre a megfelelő.Jósolj!
A jegyzet.txt létezik, tartalma Fontos adat. A kód a File.WriteAllText("jegyzet.txt", "Új szöveg") hívást hajtja végre. Mi lesz a fájl tartalma?
Jóslat ellenőrzése
Csak az Új szöveg: a WriteAllText a meglévő tartalmat felülírja, nem fűz hozzá. A hozzáfűzéshez AppendAllText kell. Ez az egyik leggyakoribb adatvesztő hiba.
Path: útvonalak építése és bontása
string ut = @"C:\Felhasznalok\Anna\Dokumentumok\jelentes.2026.docx";
Path.GetFileName(ut); // jelentes.2026.docx
Path.GetFileNameWithoutExtension(ut); // jelentes.2026
Path.GetExtension(ut); // .docx (ponttal)
Path.GetDirectoryName(ut); // C:\Felhasznalok\Anna\Dokumentumok
Path.ChangeExtension(ut, ".pdf"); // ...\jelentes.2026.pdf
// építés: SOHA ne fűzd össze kézzel (a \ jel hiányozhat vagy duplázódhat)
string mappa = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string adat = Path.Combine(mappa, "Jegyzetek", "jegyzetek.json"); // több tag is lehet
// ideiglenes fájl és mappa
string ideiglenes = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".tmp");
// teljes útvonal (a relatívból)
string teljes = Path.GetFullPath(@"adatok\naplo.txt");
// érvénytelen karakterek a fájlnévben: \ / : * ? " < > | és a vezérlőkarakterek
private string FajlnevTisztit(string nev)
{
foreach (char c in Path.GetInvalidFileNameChars())
{
nev = nev.Replace(c, '_');
}
nev = nev.Trim().TrimEnd('.'); // a Windows nem szereti a pontra végződő nevet
return nev.Length == 0 ? "nevtelen" : nev;
}Path.Combine a megfelelő elválasztót (\ Windows alatt) teszi a tagok közé. Ha egy későbbi tag abszolút útvonal (C:\... vagy \ jellel kezdődik), az eldobja az előzőket: a felhasználótól kapott mappanevet így ne fűzd mappa-elem után bizalommal (útvonal-bejárás, lásd lent)..docx). Összehasonlításhoz használj kis- és nagybetűtől független összehasonlítást: string.Equals(a, b, StringComparison.OrdinalIgnoreCase) (a Windows fájlnevei nem érzékenyek a betűnagyságra).GetInvalidFileNameChars a tiltott karaktereket adja. A felhasználó által megadott név (például egy jegyzet címe) mindig tisztítsd meg, mielőtt fájlnévnek használod."..\..\Windows" típusú név kijuthat az engedélyezett mappából. Ellenőrizd: Path.GetFullPath(Path.Combine(alap, nev)) StartsWith(alap)-e.Jósolj!
A Path.Combine(@"C:\Adatok", @"D:\Masik\fajl.txt") mit ad vissza?
Jóslat ellenőrzése
A D:\Masik\fajl.txt értéket: a második tag abszolút útvonal, ezért eldobja az elsőt. Ha a második tag felhasználói bemenet, ez biztonsági kérdés: a program a megadott mappán kívülre írhat.
Directory és DirectoryInfo
// létrehozás: a köztes mappákat is létrehozza; ha már létezik, nem hiba
Directory.CreateDirectory(Path.Combine(mappa, "Jegyzetek", "Mentesek"));
bool van = Directory.Exists(mappa);
// listázás
string[] fajlok = Directory.GetFiles(mappa, "*.txt", SearchOption.TopDirectoryOnly); // csak ebben a mappában
string[] almappak = Directory.GetDirectories(mappa);
// lusta bejárás: nagy mappánál az eredmény azonnal jön, nem várja meg a teljes listát
foreach (string f in Directory.EnumerateFiles(mappa, "*.*", SearchOption.TopDirectoryOnly))
{
lstFajlok.Items.Add(Path.GetFileName(f));
}
// mappa mérete: rekurzív összegzés, védett mappák kihagyásával
private long MappaMeret(string ut)
{
long ossz = 0;
try
{
foreach (string f in Directory.EnumerateFiles(ut)) { ossz += new FileInfo(f).Length; }
foreach (string d in Directory.EnumerateDirectories(ut)) { ossz += MappaMeret(d); }
}
catch (UnauthorizedAccessException) { } // a védett mappát kihagyjuk
catch (DirectoryNotFoundException) { }
return ossz;
}
// törlés: üres mappa, vagy teljes tartalommal (VESZÉLYES: nincs szemétkosár!)
Directory.Delete(ures);
Directory.Delete(teli, true); // rekurzív: mindent törölGetFiles a teljes listát tömbként adja (megvárja a bejárást), az EnumerateFiles lustán, soronként: nagy mappánál gyorsabban indul, és a bejárás megszakítható. Kisebb mappához mindkettő jó.AllDirectories az almappákat is bejárja. Védett mappa (például a rendszermappák) UnauthorizedAccessException kivételt dob, ami a teljes bejárást megszakítja: saját rekurzív bejárás (lásd fent) kezelheti.Directory.Delete(ut, true) mindent töröl, a szemétkosár megkerülésével. Felhasználói adatnál megerősítés kell (YesNo, Button2, 7.4 lecke), és a mappa útvonalát ellenőrizd (üres vagy gyökér útvonalnál ne fusson).Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(…, RecycleOption.SendToRecycleBin) megteszi (hivatkozás a Microsoft.VisualBasic szerelvényre), ez a megerősítés mellett biztonságosabb választás.Jósolj!
A Directory.GetFiles(@"C:\", "*.*", SearchOption.AllDirectories) hívás hogyan viselkedik egy átlagos felhasználónál?
Jóslat ellenőrzése
Hosszú ideig fut (a felület lefagy), és UnauthorizedAccessException kivétellel leáll az első védett mappánál (például System Volume Information), mielőtt visszaadná az eredményt. Nagy fát saját, kivételt kezelő rekurzióval és háttérszálon (11. fejezet) járj be.
Relatív útvonalak és hová írhat a program
A "adatok.txt" relatív útvonal a program munkamappájához viszonyul, amely nem biztos, hogy a program mappája: a fájlválasztók (RestoreDirectory = false esetén) és a parancsikon beállítása is megváltoztathatja. Ezért a program adatait sosem relatív útvonalra írd:
| Cél | Hová? | Hogyan? |
|---|---|---|
| Felhasználó dokumentuma | A felhasználó által választott hely (Dokumentumok) | Fájlválasztó, SpecialFolder.MyDocuments |
| A program saját adata, beállítása | %AppData% alatti saját mappa | SpecialFolder.ApplicationData + Path.Combine |
| Gépszintű gyorsítótár | %LocalAppData% | SpecialFolder.LocalApplicationData |
| Ideiglenes fájl | A rendszer temp mappája | Path.GetTempPath() |
| A program mellé csomagolt (csak olvasható) erőforrás | A program mappája | AppContext.BaseDirectory (régi .NET Framework: Application.StartupPath) |
// a program saját adatmappája: létrehozva, ha még nincs
private static string AdatMappa()
{
string ut = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MiniJegyzet");
Directory.CreateDirectory(ut);
return ut;
}
// a program mappája, az erőforrásfájlokhoz (a Program Files alá NE írj!)
string sablon = Path.Combine(AppContext.BaseDirectory, "sablonok", "alap.txt");Jósolj!
A program a File.WriteAllText("beallitas.txt", ...) hívással ment. A felhasználó az OpenFileDialog segítségével egy másik mappából nyitott meg fájlt, utána mentett. Hová kerül a beallitas.txt?
Jóslat ellenőrzése
Ahhoz a mappához, amely a munkamappa éppen (az OpenFileDialog a munkamappát megváltoztathatta, ha a RestoreDirectory hamis): az a mappa, ahonnan a felhasználó a fájlt megnyitotta. A beállítás „eltűnik” a következő indításkor. Ezért teljes útvonalat (AdatMappa()) használj.
Mit tegyél ide: a fájlkezelő-labor: a mappa fájlistája (név, méret, dátum), a műveletek gombjai és az állapotsor.Javasolt fájlnév: winforms-10-1-fajlkezelo.webp · Alt szöveg: A fájlkezelő-labor 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 hozzáfűzés felülírja a fájlt
File.WriteAllText(naplo, uzenet + Environment.NewLine); // minden hívás törli az előzőeketHiba és javítás
Hozzáfűzéshez File.AppendAllText kell. A WriteAllText mindig felülír.
2. DirectoryNotFoundException a mentéskor
File.WriteAllText(Path.Combine(mappa, "mentesek", "a.txt"), tartalom); // a mentesek mappa nincsHiba és javítás
A File.WriteAllText a fájlt létrehozza, a mappát nem. Előbb Directory.CreateDirectory(Path.GetDirectoryName(ut)) (nem hiba, ha már létezik).
3. A kézi útvonalfűzés hibás útvonalat ad
string ut = mappa + "adat.txt"; // C:\Mappa + adat.txt = C:\Mappaadat.txtHiba és javítás
A \ jel hiányzik. Használd a Path.Combine metódust.
4. ArgumentException a fájlnévben lévő karakter miatt
A jegyzet címe Teendő: 1/2, és a fájl mentése hibázik. A Ok és javítás
: és a / tiltott karakter a fájlnévben. Tisztítsd a nevet (FajlnevTisztit, GetInvalidFileNameChars).
5. A mentés a program mappájába hibázik telepítés után
Fejlesztéskor működik, telepítve A Program Files mappába a felhasználó nem írhat. Az adatokat a %AppData% alá mentsd (UnauthorizedAccessException jön.Ok és javítás
AdatMappa()).
6. A File.Exists után mégis hiba keletkezik
if (File.Exists(ut)) { string s = File.ReadAllText(ut); } // két lépés között a fájl eltűnhet vagy zárolt lehetHiba és javítás
A vizsgálat és a használat között a fájl változhat. A File.Exists csak jelzés: a műveletet try–catch védje (10.9 lecke).
Mini projekt: fájlkezelő-labor
Készíts kis fájlkezelőt, amely biztonságosan kezeli a fájlokat és mappákat:
- Felület: Mappa kiválasztása... (
FolderBrowserDialog, 7.8 lecke),lblMappa,lstFajlok(ListViewDetailsnézettel: Név, Méret, Módosítva) vagyDataGridView; gombok: Új mappa, Átnevezés, Másolás ide..., Áthelyezés ide..., Törlés, Mappa mérete;txtKereses(a névrészlet szerinti szűréshez); állapotsor. - Lista: a mappa fájljai és almappái (
EnumerateFiles,EnumerateDirectories), a mappák elöl, a méret olvasható alakban (B, KB, MB, 7.8 lecke), a dátumLastWriteTime; a védett fájlok adatai hibát nem okozhatnak (try–catch). - Új mappa: a név bekérése,
FajlnevTisztit, létezés-ellenőrzés (YesNofelülírás nincs: a mappa már létezik üzenet),CreateDirectory. - Átnevezés:
File.Move(fájl) ésDirectory.Move(mappa); a név tisztítása; ütközés (már létező név) kezelése; a kiterjesztés megtartása, ha a felhasználó nem ír újat. - Másolás és áthelyezés: cél mappa választása; azonos nevű fájlnál
YesNokérdés (Button2a Nem); mappa másolása rekurzívan (saját metódus). - Törlés: több kijelölés; megerősítés a darabszámmal; a mappa törlése csak tartalmával együtt, külön erős figyelmeztetéssel (a Windows-gyökér és a felhasználói mappa védett: nem törölhető).
- Mappa mérete: a rekurzív
MappaMeretkivételkezeléssel; a kihagyott (védett) mappák számát az állapotsor mutatja. - Biztonság: útvonal-bejárás elleni védelem az átnevezésnél (a név nem tartalmazhat
\jelet); nincs törlés a gyökérmappán; minden művelet hibájára érthető üzenet. - Teszteld: ékezetes és szóközös nevek, 1000 fájlos mappa, védett mappa (C:\Windows\System32\config), foglalt fájl törlése, már létező cél, nem létező mappa (időközben törölt), kijelölés nélküli gombok.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A kulcs a Muvelet segédmetódus: minden fájlművelet ezen megy át, és a tipikus kivételeket érthető szöveggé alakítja.
private string mappa = "";
private string Meret(long bajt)
{
string[] egyseg = { "B", "KB", "MB", "GB" };
double ertek = bajt;
int i = 0;
while (ertek >= 1024 && i < egyseg.Length - 1) { ertek /= 1024; i++; }
return ertek.ToString(i == 0 ? "0" : "0.#") + " " + egyseg[i];
}
private string FajlnevTisztit(string nev)
{
foreach (char c in Path.GetInvalidFileNameChars()) { nev = nev.Replace(c, '_'); }
nev = nev.Trim().TrimEnd('.');
return nev.Length == 0 ? "nevtelen" : nev;
}
// minden művelet itt megy át: a kivételek érthető szöveggé alakulnak
private bool Muvelet(Action munka, string leiras)
{
try
{
munka();
tsslUzenet.Text = leiras + ": kész.";
return true;
}
catch (UnauthorizedAccessException) { Hiba(leiras, "Nincs jogosultság ehhez a művelethez."); }
catch (DirectoryNotFoundException) { Hiba(leiras, "A mappa időközben megszűnt vagy nem elérhető."); }
catch (FileNotFoundException) { Hiba(leiras, "A fájl időközben megszűnt."); }
catch (PathTooLongException) { Hiba(leiras, "Az útvonal túl hosszú."); }
catch (IOException ex) { Hiba(leiras, "A fájl használatban van, vagy a lemez nem elérhető (" + ex.Message + ")."); }
return false;
}
private void Hiba(string leiras, string uzenet)
{
MessageBox.Show(this, uzenet, leiras, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
private void Betolt()
{
lvFajlok.Items.Clear();
if (!Directory.Exists(mappa)) { return; }
string szuro = txtKereses.Text.Trim();
try
{
foreach (string d in Directory.EnumerateDirectories(mappa))
{
string nev = Path.GetFileName(d);
if (szuro.Length == 0 || nev.IndexOf(szuro, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
ListViewItem t = new ListViewItem("📁 " + nev);
t.SubItems.Add("");
t.SubItems.Add(Directory.GetLastWriteTime(d).ToString("yyyy. MM. dd. HH:mm"));
t.Tag = d;
lvFajlok.Items.Add(t);
}
}
foreach (string f in Directory.EnumerateFiles(mappa))
{
string nev = Path.GetFileName(f);
if (szuro.Length == 0 || nev.IndexOf(szuro, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
FileInfo fi = new FileInfo(f);
ListViewItem t = new ListViewItem(nev);
t.SubItems.Add(Meret(fi.Length));
t.SubItems.Add(fi.LastWriteTime.ToString("yyyy. MM. dd. HH:mm"));
t.Tag = f;
lvFajlok.Items.Add(t);
}
}
}
catch (UnauthorizedAccessException) { Hiba("Listázás", "Ehhez a mappához nincs jogosultságod."); }
catch (IOException ex) { Hiba("Listázás", ex.Message); }
tsslUzenet.Text = lvFajlok.Items.Count + " elem";
}
private void btnMappa_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog fbd = new FolderBrowserDialog())
{
if (Directory.Exists(mappa)) { fbd.SelectedPath = mappa; }
if (fbd.ShowDialog(this) == DialogResult.OK) { mappa = fbd.SelectedPath; lblMappa.Text = mappa; Betolt(); }
}
}
private void txtKereses_TextChanged(object sender, EventArgs e) { Betolt(); }
private string Kijelolt()
{
return lvFajlok.SelectedItems.Count == 0 ? null : (string)lvFajlok.SelectedItems[0].Tag;
}
private void btnUjMappa_Click(object sender, EventArgs e)
{
if (!Directory.Exists(mappa)) { return; }
string nev = KerdesForm.Kerdez(this, "Az új mappa neve:", "Új mappa"); // saját bekérő ablak: kis Form egy TextBox-szal és OK/Mégse gombbal (7.6–7.7 lecke); Mégse esetén null
if (nev == null) { return; }
string ut = Path.Combine(mappa, FajlnevTisztit(nev));
if (Directory.Exists(ut) || File.Exists(ut)) { Hiba("Új mappa", "Ilyen nevű elem már létezik."); return; }
if (Muvelet(() => Directory.CreateDirectory(ut), "Új mappa")) { Betolt(); }
}
private void btnAtnevez_Click(object sender, EventArgs e)
{
string regi = Kijelolt();
if (regi == null) { return; }
string nev = KerdesForm.Kerdez(this, "Az új név:", Path.GetFileName(regi));
if (nev == null) { return; }
nev = FajlnevTisztit(nev);
if (File.Exists(regi) && Path.GetExtension(nev).Length == 0) { nev += Path.GetExtension(regi); } // a kiterjesztés megmarad
string uj = Path.Combine(Path.GetDirectoryName(regi), nev);
if (File.Exists(uj) || Directory.Exists(uj)) { Hiba("Átnevezés", "Ilyen nevű elem már létezik."); return; }
if (Muvelet(() => { if (File.Exists(regi)) { File.Move(regi, uj); } else { Directory.Move(regi, uj); } }, "Átnevezés")) { Betolt(); }
}
private void MappaMasol(string forras, string cel)
{
Directory.CreateDirectory(cel);
foreach (string f in Directory.EnumerateFiles(forras)) { File.Copy(f, Path.Combine(cel, Path.GetFileName(f)), false); }
foreach (string d in Directory.EnumerateDirectories(forras)) { MappaMasol(d, Path.Combine(cel, Path.GetFileName(d))); }
}
private void btnMasol_Click(object sender, EventArgs e)
{
string forras = Kijelolt();
if (forras == null) { return; }
using (FolderBrowserDialog fbd = new FolderBrowserDialog())
{
if (fbd.ShowDialog(this) != DialogResult.OK) { return; }
string cel = Path.Combine(fbd.SelectedPath, Path.GetFileName(forras));
if (File.Exists(cel) && MessageBox.Show(this, "A célmappában már van ilyen fájl. Felülírod?", "Másolás", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes) { return; }
Muvelet(() => { if (File.Exists(forras)) { File.Copy(forras, cel, true); } else { MappaMasol(forras, cel); } }, "Másolás");
}
}
private bool Vedett(string ut)
{
string teljes = Path.GetFullPath(ut).TrimEnd(Path.DirectorySeparatorChar);
string gyoker = Path.GetPathRoot(teljes).TrimEnd(Path.DirectorySeparatorChar);
string felh = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile).TrimEnd(Path.DirectorySeparatorChar);
string win = Environment.GetFolderPath(Environment.SpecialFolder.Windows).TrimEnd(Path.DirectorySeparatorChar);
return string.Equals(teljes, gyoker, StringComparison.OrdinalIgnoreCase) || string.Equals(teljes, felh, StringComparison.OrdinalIgnoreCase) || teljes.StartsWith(win, StringComparison.OrdinalIgnoreCase);
}
private void btnTorol_Click(object sender, EventArgs e)
{
List<string> utak = lvFajlok.SelectedItems.Cast<ListViewItem>().Select(t => (string)t.Tag).ToList();
if (utak.Count == 0) { return; }
if (utak.Any(Vedett)) { Hiba("Törlés", "Védett mappa nem törölhető."); return; }
bool vanMappa = utak.Any(Directory.Exists);
string kerdes = utak.Count + " elem törlése" + (vanMappa ? " (mappa a tartalmával együtt, véglegesen!)" : "") + ". Biztosan?";
if (MessageBox.Show(this, kerdes, "Törlés", MessageBoxButtons.YesNo, vanMappa ? MessageBoxIcon.Stop : MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes) { return; }
foreach (string ut in utak)
{
Muvelet(() => { if (File.Exists(ut)) { File.Delete(ut); } else if (Directory.Exists(ut)) { Directory.Delete(ut, true); } }, "Törlés");
}
Betolt();
}
private long kihagyott = 0;
private long MappaMeret(string ut)
{
long ossz = 0;
try
{
foreach (string f in Directory.EnumerateFiles(ut)) { ossz += new FileInfo(f).Length; }
foreach (string d in Directory.EnumerateDirectories(ut)) { ossz += MappaMeret(d); }
}
catch (UnauthorizedAccessException) { kihagyott++; }
catch (IOException) { kihagyott++; }
return ossz;
}
private void btnMeret_Click(object sender, EventArgs e)
{
string ut = Kijelolt() != null && Directory.Exists(Kijelolt()) ? Kijelolt() : mappa;
if (!Directory.Exists(ut)) { return; }
kihagyott = 0;
Cursor = Cursors.WaitCursor;
long meret = MappaMeret(ut);
Cursor = Cursors.Default;
tsslUzenet.Text = Path.GetFileName(ut) + ": " + Meret(meret) + (kihagyott > 0 ? " (" + kihagyott + " védett mappa kihagyva)" : "");
}Mit tegyél ide: a kész fájlkezelő-labor egy mappa tartalmával és a mérettel az állapotsorban.Javasolt fájlnév: winforms-10-1-kesz.webp · Alt szöveg: A kész fájlkezelő-labor
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. Egyedi fájlnév
Ha a Ciklus, amely a számot növeli, amíg a név szabad. A jelentes.txt már létezik, a program a jelentes (2).txt, jelentes (3).txt nevet válassza. Hogyan?Egy lehetséges megoldás
Path.GetFileNameWithoutExtension és GetExtension bontja a nevet.private string EgyediUtvonal(string ut){ string mappa = Path.GetDirectoryName(ut); string nev = Path.GetFileNameWithoutExtension(ut); string kit = Path.GetExtension(ut); int i = 2; while (File.Exists(ut)) { ut = Path.Combine(mappa, nev + " (" + i + ")" + kit); i++; } return ut;}
2. Fájlok rendezése kiterjesztés szerint
Egy mappa fájljait másold a kiterjesztés nevű almappákba (txt, png…). Mire kell vigyáznod? A kiterjesztés nélküli fájlra (egyéb mappa), az azonos nevű ütközésre (Egy lehetséges megoldás
EgyediUtvonal), a kis- és nagybetűre (.JPG és .jpg ugyanaz), és a hibás fájlok átugrására.
3. Régi fájlok keresése
Keresd meg a mappában a 1 évnél régebben módosított, 10 MB-nál nagyobb fájlokat. Mit használsz? A Egy lehetséges megoldás
DirectoryInfo.EnumerateFiles FileInfo objektumokat ad: LINQ Where a LastWriteTime és Length szerint.DirectoryInfo di = new DirectoryInfo(mappa);var regiek = di.EnumerateFiles().Where(f => f.LastWriteTime < DateTime.Now.AddYears(-1) && f.Length > 10 * 1024 * 1024).OrderByDescending(f => f.Length).ToList();
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. Path bontás
Mi a jegyzet.v2: csak az utolsó kiterjesztést (Path.GetFileNameWithoutExtension(@"C:\A\B\jegyzet.v2.txt") értéke?Megoldás megnyitása
.txt) hagyja el.
2. Melyik metódus?
Melyiket használod: (a) hozzáfűzés a naplóhoz; (b) átnevezés; (c) mappa létrehozása köztes mappákkal? (a) Megoldás megnyitása
File.AppendAllText; (b) File.Move (Directory.Move); (c) Directory.CreateDirectory.
Közepes szint
3. Kiterjesztés összehasonlítása
Hogyan döntöd el, hogy egy fájl kép-e ( A .png, .jpg, .jpeg), betűnagyságtól függetlenül?Megoldás megnyitása
Path.GetExtension(f).ToLowerInvariant() egy tömb (HashSet) elemeivel összevetve.HashSet<string> kepek = new HashSet<string> { ".png", ".jpg", ".jpeg" };bool kep = kepek.Contains(Path.GetExtension(f).ToLowerInvariant());
4. Útvonal-bejárás védelme
A felhasználó a A teljes útvonalat (..\..\titok.txt nevet adja meg. Hogyan akadályozod meg, hogy kilépjen az adatmappából?Megoldás megnyitása
GetFullPath) összeveted az alapmappa teljes útvonalával: StartsWith.string alap = Path.GetFullPath(adatMappa) + Path.DirectorySeparatorChar;string cel = Path.GetFullPath(Path.Combine(adatMappa, nev));if (!cel.StartsWith(alap, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Érvénytelen útvonal."); }
Kihívás szint
5. Duplikált fájlok
Keresd meg egy mappában az azonos tartalmú fájlokat. Hogyan lesz hatékony? Előbb a méret szerint csoportosítasz (az eltérő méretűek nem azonosak), és csak az azonos méretűeknél számolsz tartalmi ujjlenyomatot (hash, például SHA-256). A nagy fájloknál a hash számítása lassú: háttérszálon fusson (11. fejezet).Megoldás megnyitása
6. Figyelő a mappán
A program észlelje, ha a mappában új fájl jelenik meg. Mi a megoldás? A Megoldás megnyitása
FileSystemWatcher osztály (Created, Changed, Deleted, Renamed események). Az események másik szálon érkeznek: a felület frissítéséhez Invoke kell (11. fejezet).
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. A Ha egy fájl több adatát (méret, dátum, név) kérdezed le, vagy objektumként kezeled. A megfelelő elválasztót teszi, nem hibázik kézi fűzésnél. A A %AppData% alatti saját mappába, nem a program mappájába vagy relatív útvonalra. Mindent töröl, a szemétkosár nélkül: megerősítés és útvonal-ellenőrzés kell. Nem: a vizsgálat és a használat között a fájl változhat; 1. Mi a különbség a WriteAllText és az AppendAllText között?
WriteAllText felülír, az AppendAllText a végére fűz.2. Mikor használsz FileInfo-t?
3. Miért Path.Combine?
4. Hogyan kezeled a tiltott karaktereket a fájlnévben?
Path.GetInvalidFileNameChars karaktereit lecseréled.5. Hová mentsd a program adatait?
6. Miért veszélyes a Directory.Delete(ut, true)?
7. Elég a File.Exists a hibák ellen?
try–catch kell.
Mit tudsz már?
- Használod a
File,FileInfo,Directoryosztályok metódusait. - Útvonalat építesz és bontasz a
Pathosztállyal, és tisztítod a fájlneveket. - Mappát hozol létre, listázol, másolsz és törölsz, védett mappák kezelésével.
- Tudod, hová írhat a program, és elkerülöd a relatív útvonal csapdáit.
- A műveleteket kivételkezeléssel és érthető üzenetekkel védd.
Következő lecke: StreamReader, StreamWriter és using
Fájlok olvasása és írása adatfolyamként: soronként, nagy fájlokkal, a using és az FileStream szerepével.



