Grafikus C# – Windows Forms tanfolyam › 7.8 lecke

Windows Forms · 7.8 lecke · fájl- és mappaválasztók

OpenFileDialog, SaveFileDialog és FolderBrowserDialog

A fájlok megnyitásához, mentéséhez és a mappák kiválasztásához a Windows kész párbeszédablakokat ad, amelyeket a felhasználók ismernek és szeretnek: nem kell saját fájlböngészőt írnod. A 2.2 és 2.3 leckében a OpenFileDialog és SaveFileDialog alapjait már használtad a MiniWordben. Most a teljes tudásukat: a szűrők (Filter), a kezdőmappa és az utolsó mappa megjegyzése, a többes kijelölés, a felülírás-védelem, a FolderBrowserDialog, a különleges mappák és a hibák kezelése.

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

A lecke végére

  • helyes szűrő-sztringet írsz (Filter, FilterIndex), és kezeled a kiválasztott szűrőt;
  • beállítod a kezdőmappát, a címet, az ellenőrzéseket (CheckFileExists), és megjegyzed az utolsó mappát;
  • többes kijelölést (Multiselect, FileNames) és mentést felülírás-védelemmel (OverwritePrompt, DefaultExt) használsz;
  • a FolderBrowserDialog segítségével mappát választasz, és a különleges mappákat (SpecialFolder) használod;
  • a fájlok adatait a FileInfo osztállyal olvasod, és olvasható méretet írsz ki;
  • kezeled a gyakori hibákat (IOException, UnauthorizedAccessException, hibás szűrő).

Mielőtt elkezded

Ehhez a leckéhez a 2.2–2.3 lecke (OpenFileDialog, SaveFileDialog első használata), a 7.4 lecke (MessageBox) és az 5.6 lecke (Settings) szükséges. A fájlkezelés részleteit (File, Path, Directory) a 10. fejezet tárgyalja, itt csak a szükséges alapokat használjuk.

7.7 Adatátadás →

OpenFileDialog: fájl megnyitása

TulajdonságJelentése
FilterA fájltípus-szűrők: "Felirat|minta|Felirat|minta" alakban, páronként (például "Szövegfájlok (*.txt)|*.txt|Minden fájl (*.*)|*.*").
FilterIndexMelyik szűrő van kiválasztva induláskor (1-től számozva!). A felhasználó választása után is kiolvasható.
InitialDirectoryA kezdőmappa.
FileNameAz alapértelmezett (majd a kiválasztott) fájl neve, teljes útvonallal OK után.
TitleAz ablak címe.
CheckFileExists, CheckPathExistsCsak létező fájlt (mappát) enged választani (alapból igaz).
Multiselect, FileNamesTöbb fájl kijelölése; a kiválasztottak tömbje.
RestoreDirectoryAz ablak bezárásakor visszaállítja az eredeti munkamappát (hasznos, ha a program relatív útvonalakat használ).
Form1.cs (using System.IO;)C#
private void miMegnyit_Click(object sender, EventArgs e)
{
using (OpenFileDialog ablak = new OpenFileDialog())
{
ablak.Title = "Dokumentum megnyitása";
ablak.Filter = "Szövegfájlok (*.txt)|*.txt|Rich Text (*.rtf)|*.rtf|Minden fájl (*.*)|*.*";
ablak.FilterIndex = 1; // az első szűrő (1-től indul!)
ablak.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
ablak.CheckFileExists = true;
ablak.Multiselect = false;

if (ablak.ShowDialog(this) != DialogResult.OK)
{
return; // Mégse: nincs teendő
}

string utvonal = ablak.FileName;

try
{
rtbSzoveg.Text = File.ReadAllText(utvonal);
tsslUzenet.Text = "Megnyitva: " + Path.GetFileName(utvonal);
}
catch (Exception ex)
{
MessageBox.Show(this, "A fájl nem nyitható meg." + Environment.NewLine + ex.Message, "Megnyitás", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
A szűrő párosA Filter szövege mindig páros számú részből áll (felirat és minta). Az utolsó pár után nincs |. A több minta pontosvesszővel (*.png;*.jpg) adható meg egy szűrőben.
using vagy komponensA tervezőben az eszköztárról a formra húzott OpenFileDialog komponens az ablak components gyűjteményében van, és az ablakkal együtt szabadul fel. Kódból létrehozva using kell (7.5 lecke).
FileName teljes útvonalAz OK után a FileName a fájl teljes útvonala (C:\Mappa\fajl.txt), a SafeFileName csak a neve. A mappa a Path.GetDirectoryName hívással kapható.
MégseCsak az OK eredménynél dolgozz a fájllal. A Cancel a felhasználó szándékos döntése, nem hiba.

Jósolj!

A Filter értéke "Szöveg (*.txt)|*.txt|Képek" (az utolsó mintapár hiányzik). Mi történik a ShowDialog hívásakor?

Jóslat ellenőrzése

A hibás szűrő-sztring (páratlan számú rész) miatt a Filter beállítása vagy a ShowDialog ArgumentException kivételt dob (a szűrő nem érvényes). A hiba csak futáskor derül ki, ezért érdemes a szűrőt gondosan felépíteni (lásd a Gyakorlótárat), és egyszer kipróbálni.

SaveFileDialog: mentés

TulajdonságJelentése
Filter, FilterIndexMint a megnyitásnál; a kiválasztott szűrő adja a javasolt kiterjesztést.
FileNameA javasolt fájlnév (például a dokumentum jelenlegi neve).
DefaultExtA kiterjesztés (pont nélkül: "txt"), amelyet a rendszer hozzáfűz, ha a felhasználó nem ír.
AddExtensionHozzáadja-e a kiterjesztést (alapból igaz).
OverwritePromptLétező fájl felülírása előtt rákérdez (alapból igaz). Hagyd bekapcsolva.
CreatePromptNem létező fájl létrehozása előtt kérdez (alapból hamis).
Form1.csC#
private bool MentesMaskent()
{
using (SaveFileDialog ablak = new SaveFileDialog())
{
ablak.Title = "Mentés másként";
ablak.Filter = "Szövegfájlok (*.txt)|*.txt|Minden fájl (*.*)|*.*";
ablak.DefaultExt = "txt";
ablak.AddExtension = true;
ablak.OverwritePrompt = true;
ablak.FileName = fajl.Length == 0 ? "Névtelen" : Path.GetFileName(fajl);

if (fajl.Length > 0)
{
ablak.InitialDirectory = Path.GetDirectoryName(fajl); // a jelenlegi fájl mappája
}

if (ablak.ShowDialog(this) != DialogResult.OK)
{
return false;
}

try
{
File.WriteAllText(ablak.FileName, rtbSzoveg.Text);
fajl = ablak.FileName;
return true;
}
catch (Exception ex)
{
MessageBox.Show(this, "A mentés nem sikerült." + Environment.NewLine + ex.Message, "Mentés", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
}
Mentés és Mentés máskéntA Mentés parancs ismert fájlnévnél közvetlenül ment, névtelennél a Mentés másként ablakot nyitja (a fenti metódus). A mentés eredménye bool: a hívó (bezárás, új dokumentum) ebből tudja, folytathat-e (7.4 lecke).
KiterjesztésA DefaultExt a .txt kiterjesztést automatikusan hozzáfűzi, ha a felhasználó nem ír. A kiválasztott szűrő is befolyásolja (a FilterIndex alapján).
Felülírás védelemAz OverwritePrompt a rendszer saját kérdése: nem kell külön MessageBox. Ha az OverwritePrompt hamis, te vagy felelős az adatvesztésért.
Hely az útvonalbanA felhasználó írhat nem létező mappát is: a rendszer ezt a CheckPathExists alapján ellenőrzi (alapból igaz), de a fájl írásakor akkor is előfordulhat hiba (jogosultság, lemez telt), ezért a mentés try–catch védelmet kap.

Jósolj!

A SaveFileDialog DefaultExt értéke "txt", a felhasználó a jegyzet nevet írja be, és az Összes fájl (*.*) szűrő van kiválasztva. Milyen néven jön létre a fájl?

Jóslat ellenőrzése

A jegyzet.txt (a DefaultExt hozzáfűzi, mert a felhasználó nem adott kiterjesztést). Ha a felhasználó jegyzet.doc nevet ír, azt a rendszer megtartja, nem írja át .txt kiterjesztésre: a kiterjesztés ellenőrzése a program dolga lehet.

FolderBrowserDialog: mappa választása

A FolderBrowserDialog mappát (nem fájlt) választ: másolás céljához, képek mappájához, adatmappához. Fontosabb tulajdonságai:

TulajdonságJelentése
DescriptionA mappafa fölött megjelenő magyarázat.
SelectedPathA kezdetben kijelölt mappa, majd az OK után a választott mappa útvonala.
RootFolderA fa gyökere (Environment.SpecialFolder érték, például MyComputer, Desktop).
ShowNewFolderButtonMegjelenjen-e az Új mappa gomb.
Form1.csC#
private string MappaValaszt(string cim, string kezdo)
{
using (FolderBrowserDialog ablak = new FolderBrowserDialog())
{
ablak.Description = cim;
ablak.ShowNewFolderButton = true;

if (Directory.Exists(kezdo))
{
ablak.SelectedPath = kezdo; // az utolsó használt mappa kijelölve
}

return ablak.ShowDialog(this) == DialogResult.OK ? ablak.SelectedPath : null;
}
}

// használat: az utolsó mappa megjegyzése a Settings-ben (5.6 lecke)
string mappa = MappaValaszt("Válaszd ki a képek mappáját.", Properties.Settings.Default.UtolsoMappa);

if (mappa != null)
{
Properties.Settings.Default.UtolsoMappa = mappa;
Properties.Settings.Default.Save();
}

Újabb .NET: modernabb mappaválasztó

A FolderBrowserDialog hagyományos, kicsit régies kinézetű (mappafa). Az újabb .NET-verziókban (a .NET 8 körül) megjelent egy modernebb, a fájlválasztóhoz hasonló mappaválasztó (OpenFolderDialog). Hogy a használt projekted támogatja-e, a verziótól függ: ellenőrizd az Eszköztárban és az IntelliSense-ben. A FolderBrowserDialog minden verzióban működik.

Jósolj!

A SelectedPath kezdőértéke egy már nem létező mappa (a felhasználó törölte). Mit csinál az ablak?

Jóslat ellenőrzése

A nem létező kezdőmappát a rendszer figyelmen kívül hagyja, és az ablak a gyökérnél (vagy az utolsó ismert helyen) nyílik meg, de a viselkedés verziófüggő lehet. Ezért a kezdőmappát előbb ellenőrizd (Directory.Exists), és csak létező értéket adj meg.

Különleges mappák, fájladatok, hibák

Form1.csC#
// különleges mappák: a felhasználó dokumentumai, asztala, az alkalmazásadatok
string dokumentumok = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string asztal = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string adat = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); // a program saját adatainak helye

// fájladatok
FileInfo info = new FileInfo(utvonal);
lblMeret.Text = Meret(info.Length); // bájtban
lblDatum.Text = info.LastWriteTime.ToString("yyyy. MM. dd. HH:mm");

// az olvasható méret
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 = ertek / 1024;
i++;
}

return ertek.ToString(i == 0 ? "0" : "0.#") + " " + egyseg[i];
}
HibaMikor?Üzenet a felhasználónak
FileNotFoundException, DirectoryNotFoundExceptionA fájl időközben törlődött, vagy az útvonal érvénytelen.„A fájl nem található. Lehet, hogy áthelyezték vagy törölték.”
UnauthorizedAccessExceptionNincs jogosultság (védett mappa, csak olvasható fájl).„Nincs jogosultság a mentéshez. Válassz másik mappát.”
IOExceptionA fájlt másik program használja, a lemez tele van.„A fájl nem érhető el. Lehet, hogy másik program használja.”
ArgumentExceptionÉrvénytelen karakter az útvonalban, hibás szűrő.„Az útvonal vagy a fájlnév érvénytelen.”
Dokumentumok és AppDataA felhasználói fájlok alapmappája a MyDocuments. A program saját beállításai és adatai az ApplicationData alá való, nem a program mappájába (ott a felhasználónak nincs mindig írási joga).
Az ellenőrzés nem védA File.Exists vizsgálat után a fájl még törlődhet: a try–catch nélkülözhetetlen (13. fejezet).
Nagy fájlokA File.ReadAllText az egész fájlt a memóriába tölti. Néhány MB felett érdemes a méretet ellenőrizni, és figyelmeztetni a felhasználót (FileInfo.Length).
Utolsó mappaA felhasználó az utolsó használt mappában szeretne folytatni: a megnyitás és mentés után Path.GetDirectoryName értékét tárold a Settings-ben.

Jósolj!

A program a mentést a program saját mappájába végzi (C:\Program Files\...), a felhasználó pedig nem rendszergazda. Mi történik a mentéskor?

Jóslat ellenőrzése

UnauthorizedAccessException (nincs írási jog a védett mappában). A felhasználói adatokat a felhasználó mappáiba (MyDocuments, ApplicationData) kell menteni. Ezért fontos a SpecialFolder használata a fix útvonal helyett (14. fejezet).

📷 Képernyőkép helye

Mit tegyél ide: a Mentés másként ablak a szűrőkkel (Szövegfájlok, Minden fájl) és az Új mappa gombbal.Javasolt fájlnév: winforms-7-8-ment.webp · Alt szöveg: A Mentés másként párbeszédablak

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. ArgumentException a Filter beállításakor

ofd.Filter = "Szöveg|*.txt|Képek";   // páratlan számú rész
Hiba és javítás

A szűrő felirat–minta párokból áll: "Szöveg|*.txt|Képek|*.png;*.jpg".

2. A fájlt akkor is feldolgozza, ha a felhasználó a Mégse gombot nyomta

ofd.ShowDialog();
File.ReadAllText(ofd.FileName); // Mégse esetén üres a FileName
Hiba és javítás

Vizsgáld az eredményt: if (ofd.ShowDialog(this) == DialogResult.OK) { ... }.

3. A mentett fájlnak nincs kiterjesztése

A felhasználó beír egy nevet, és a fájl kiterjesztés nélkül jön létre.

Ok és javítás

A DefaultExt vagy az AddExtension nincs beállítva. Állítsd be a DefaultExt = "txt" értéket, és hagyd bekapcsolva az AddExtension tulajdonságot.

4. A felhasználó adatai elvesznek felülíráskor

A mentés csendben felülír egy meglévő fájlt.

Ok és javítás

Az OverwritePrompt = false kikapcsolta a rendszer kérdését. Hagyd alapértéken (igaz), vagy kérdezz saját üzenettel.

5. A program mindig ugyanabban a mappában nyílik meg

A felhasználó az előző mappában szeretne folytatni.

Ok és javítás

Az InitialDirectory fix. Tárold a legutóbbi mappát (Settings), és add át a megnyitás előtt (ellenőrizd, hogy létezik-e).

6. UnauthorizedAccessException a program mappájába mentve

A mentés a telepített program mappájában hibát ad.

Ok és javítás

A program mappája védett. Használj felhasználói mappát: Environment.SpecialFolder.MyDocuments vagy ApplicationData.

Mini projekt: mappaböngésző

Készíts programot, amely egy kiválasztott mappa fájljait listázza és kezeli:

  1. Mappa: a Mappa kiválasztása... gomb FolderBrowserDialog-ot nyit (a Settings-ben tárolt utolsó mappával kezdi); az útvonal egy lblMappa címkében látszik.
  2. Szűrő: cmbSzuro (Minden fájl, Szövegek (*.txt;*.md), Képek (*.png;*.jpg;*.jpeg)), rendezés: cmbRendez (Név, Méret, Dátum). A lista (lstFajlok) a szűrő és a rendezés szerint frissül.
  3. Részletek: a kijelölt fájlról a lblReszletek mutatja a nevet, az olvasható méretet, a módosítás dátumát és az útvonalat.
  4. Másolás: a Másolás ide... gomb a kijelölt fájlt egy másik mappába másolja (FolderBrowserDialog); ha létezik ugyanolyan nevű fájl, YesNo üzenet kérdez (Button2 a Nem).
  5. Fájlok hozzáadása: az Egyedi fájlok... gomb OpenFileDialog (Multiselect) segítségével további fájlokat tesz a listába, amely külön lstEgyedi listában jelenik meg.
  6. Lista mentése: a Lista mentése... gomb SaveFileDialog-gal szövegfájlba menti a fájlok nevét és méretét.
  7. Minden fájlművelet try–catch védelmet kap; a hibákra érthető üzenet jelenik meg, az állapotsor tájékoztat.
  8. Teszteld: több mappa, minden szűrő és rendezés, nagy mappa, üres mappa, védett mappa (hiba), másolás meglévő fájlra (Igen/Nem), a lista mentése és megnyitása.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A fájlok List<FileInfo> gyűjteménybe kerülnek, a rendezés a Sort metódus lambdájával történik. A szűrő mintái pontosvesszővel vannak elválasztva, minden mintára külön Directory.GetFiles hívás fut.

Form1.cs (using System.IO; using System.Collections.Generic;)C#
private string mappa = "";
private List<FileInfo> fajlok = new List<FileInfo>();

private readonly string[] mintak = { "*.*", "*.txt;*.md", "*.png;*.jpg;*.jpeg" };

private void Form1_Load(object sender, EventArgs e)
{
cmbSzuro.Items.AddRange(new object[] { "Minden fájl", "Szövegek (*.txt;*.md)", "Képek (*.png;*.jpg;*.jpeg)" });
cmbRendez.Items.AddRange(new object[] { "Név", "Méret", "Dátum" });
cmbSzuro.SelectedIndex = 0;
cmbRendez.SelectedIndex = 0;

string mentett = Properties.Settings.Default.UtolsoMappa;

if (Directory.Exists(mentett))
{
mappa = mentett;
Betolt();
}
}

private string MappaValaszt(string cim, string kezdo)
{
using (FolderBrowserDialog ablak = new FolderBrowserDialog())
{
ablak.Description = cim;

if (Directory.Exists(kezdo))
{
ablak.SelectedPath = kezdo;
}

return ablak.ShowDialog(this) == DialogResult.OK ? ablak.SelectedPath : null;
}
}

private void btnMappa_Click(object sender, EventArgs e)
{
string uj = MappaValaszt("Válaszd ki a böngészendő mappát.", mappa);

if (uj != null)
{
mappa = uj;
Properties.Settings.Default.UtolsoMappa = mappa;
Properties.Settings.Default.Save();
Betolt();
}
}

private void Betolt()
{
lblMappa.Text = mappa;
fajlok.Clear();

try
{
foreach (string minta in mintak[cmbSzuro.SelectedIndex].Split(';'))
{
foreach (string ut in Directory.GetFiles(mappa, minta, SearchOption.TopDirectoryOnly))
{
fajlok.Add(new FileInfo(ut));
}
}
}
catch (UnauthorizedAccessException)
{
MessageBox.Show(this, "Ehhez a mappához nincs jogosultságod.", "Mappa", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch (IOException ex)
{
MessageBox.Show(this, "A mappa nem olvasható: " + ex.Message, "Mappa", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Rendez();
}

private void Rendez()
{
switch (cmbRendez.SelectedIndex)
{
case 1:
fajlok.Sort((a, b) => b.Length.CompareTo(a.Length)); // a legnagyobb elöl
break;

case 2:
fajlok.Sort((a, b) => b.LastWriteTime.CompareTo(a.LastWriteTime)); // a legfrissebb elöl
break;

default:
fajlok.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
break;
}

lstFajlok.Items.Clear();

foreach (FileInfo f in fajlok)
{
lstFajlok.Items.Add(f.Name + " (" + Meret(f.Length) + ")");
}

tsslUzenet.Text = fajlok.Count + " fájl";
}

private void SzuroVagyRendez_Changed(object sender, EventArgs e)
{
if (mappa.Length == 0) { return; }

if (sender == cmbSzuro) { Betolt(); } else { Rendez(); }
}

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 = ertek / 1024;
i++;
}

return ertek.ToString(i == 0 ? "0" : "0.#") + " " + egyseg[i];
}

private void lstFajlok_SelectedIndexChanged(object sender, EventArgs e)
{
int i = lstFajlok.SelectedIndex;

if (i < 0)
{
lblReszletek.Text = "";
return;
}

FileInfo f = fajlok[i];
lblReszletek.Text = $"Név: {f.Name}{Environment.NewLine}Méret: {Meret(f.Length)}{Environment.NewLine}Módosítva: {f.LastWriteTime:yyyy. MM. dd. HH:mm}{Environment.NewLine}Útvonal: {f.FullName}";
}

private void btnMasol_Click(object sender, EventArgs e)
{
int i = lstFajlok.SelectedIndex;

if (i < 0) { return; }

string cel = MappaValaszt("Hova másolod a fájlt?", mappa);

if (cel == null) { return; }

string celUt = Path.Combine(cel, fajlok[i].Name);

if (File.Exists(celUt) && MessageBox.Show(this, "A célmappában már van ilyen nevű fájl. Felülírod?", "Másolás", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes)
{
return;
}

try
{
File.Copy(fajlok[i].FullName, celUt, true);
tsslUzenet.Text = "Másolva: " + celUt;
}
catch (Exception ex)
{
MessageBox.Show(this, "A másolás nem sikerült: " + ex.Message, "Másolás", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

private void btnEgyedi_Click(object sender, EventArgs e)
{
using (OpenFileDialog ablak = new OpenFileDialog())
{
ablak.Title = "Fájlok kiválasztása";
ablak.Filter = "Minden fájl (*.*)|*.*";
ablak.Multiselect = true;

if (Directory.Exists(mappa))
{
ablak.InitialDirectory = mappa;
}

if (ablak.ShowDialog(this) == DialogResult.OK)
{
foreach (string ut in ablak.FileNames)
{
lstEgyedi.Items.Add(ut);
}
}
}
}

private void btnListaMent_Click(object sender, EventArgs e)
{
using (SaveFileDialog ablak = new SaveFileDialog())
{
ablak.Filter = "Szövegfájlok (*.txt)|*.txt";
ablak.DefaultExt = "txt";
ablak.FileName = "fajllista";

if (ablak.ShowDialog(this) != DialogResult.OK) { return; }

List<string> sorok = new List<string>();

foreach (FileInfo f in fajlok)
{
sorok.Add(f.Name + ";" + f.Length);
}

try
{
File.WriteAllLines(ablak.FileName, sorok);
tsslUzenet.Text = "Lista mentve: " + ablak.FileName;
}
catch (Exception ex)
{
MessageBox.Show(this, "A lista mentése nem sikerült: " + ex.Message, "Mentés", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
📷 Képernyőkép helye

Mit tegyél ide: a mappaböngésző a fájllistával, a részletekkel és a szűrő/rendezés választókkal.Javasolt fájlnév: winforms-7-8-kesz.webp · Alt szöveg: A mappaböngésző program

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. Szűrő felépítése listából

Írj segédmetódust, amely egy típuslistából (Szöveg: txt, md; Kép: png, jpg) építi fel a Filter szöveget, a pontos formátumban. Miért jobb a kézi írásnál?

Egy lehetséges megoldás

Nincs pár- vagy elválasztóhiba. A metódus elejére tehetsz egy Minden támogatott szűrőt is.

Form1.csC#
private string SzuroEpit(string[] nevek, string[][] kiterjesztesek)
{
List<string> reszek = new List<string>();

for (int i = 0; i < nevek.Length; i++)
{
List<string> mintak = new List<string>();

foreach (string k in kiterjesztesek[i])
{
mintak.Add("*." + k);
}

string minta = string.Join(";", mintak);
reszek.Add(nevek[i] + " (" + minta + ")|" + minta);
}

reszek.Add("Minden fájl (*.*)|*.*");
return string.Join("|", reszek);
}

2. Mentés másként a szűrő szerinti kiterjesztéssel

A SaveFileDialog szűrői: Szöveg (*.txt), Markdown (*.md). Mentés után ellenőrizd, hogy a fájl kiterjesztése megegyezik-e a választott szűrővel, és ha nem, egészítsd ki. Hogyan?

Egy lehetséges megoldás

A FilterIndex (1-től) alapján a kívánt kiterjesztés kiválasztható; a Path.ChangeExtension módosítja, ha a felhasználó mást írt (vagy kiegészíti, ha nincs).

Form1.csC#
string[] kit = { ".txt", ".md" };
string ut = sfd.FileName;
string kivant = kit[sfd.FilterIndex - 1];

if (!Path.GetExtension(ut).Equals(kivant, StringComparison.OrdinalIgnoreCase))
{
ut = ut + kivant; // kiegészítés (nem cserélünk meglévő kiterjesztést)
}

3. Utolsó fájl megnyitása indításkor

A program induláskor megnyitja az utoljára használt fájlt (ha létezik). Hol tárolod az útvonalat, és mit teszel, ha a fájl közben eltűnt?

Egy lehetséges megoldás

A Settings-ben (UtolsoFajl), a Load-ban megnyitva, File.Exists és try–catch védelemmel. Ha eltűnt, csendben kihagyja (az állapotsor jelezhet).

Form1.csC#
private void Form1_Load(object sender, EventArgs e)
{
string ut = Properties.Settings.Default.UtolsoFajl;

if (ut.Length > 0 && File.Exists(ut))
{
try
{
rtbSzoveg.Text = File.ReadAllText(ut);
fajl = ut;
}
catch (IOException)
{
tsslUzenet.Text = "Az utolsó fájl nem nyitható meg.";
}
}
}

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. Filter

Írd meg a szűrő-sztringet: Képek (png, jpg), Minden fájl.

Megoldás megnyitása

"Képek (*.png;*.jpg)|*.png;*.jpg|Minden fájl (*.*)|*.*". Négy rész: két felirat, két minta.

2. Eredmények

Mit ad a ShowDialog, ha a felhasználó a Mégse gombot nyomja? Mi a FileName értéke ilyenkor?

Megoldás megnyitása

DialogResult.Cancel. A FileName az előző (vagy üres) érték, ezért nem szabad használni.

Közepes szint

3. Több fájl megnyitása

Egy Multiselect ablak a kiválasztott fájlok neveit és méretét egy listába írja. Melyik tulajdonságot használod, és miért nem a FileName-et?

Megoldás megnyitása

A FileNames tömböt (az összes kiválasztott útvonal). A FileName csak az elsőt adja.

Form1.csC#
foreach (string ut in ofd.FileNames)
{
FileInfo f = new FileInfo(ut);
lstFajlok.Items.Add(f.Name + " (" + f.Length + " bájt)");
}

4. Mentés a felhasználó mappájába

Készíts mentési útvonalat a Dokumentumok mappán belüli MiniProgram almappába. Mit kell megoldanod, ha az almappa még nincs meg?

Megoldás megnyitása

A Directory.CreateDirectory létrehozza (ha már megvan, nem csinál semmit), a Path.Combine építi az útvonalat.

Form1.csC#
string alap = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string mappa = Path.Combine(alap, "MiniProgram");

Directory.CreateDirectory(mappa); // létrehozza, ha hiányzik

File.WriteAllText(Path.Combine(mappa, "adat.txt"), tartalom);

Kihívás szint

5. Húzd és ejtsd fájl nyitásra

A szerkesztőbe húzott fájl megnyílik (Drag and Drop, 5.3 lecke). Hogyan olvasod ki a húzott fájlok útvonalát?

Megoldás megnyitása

AllowDrop = true, a DragEnter eseményben a DataFormats.FileDrop ellenőrzése, a DragDrop eseményben GetData(DataFormats.FileDrop) a string[] tömb.

Form1.csC#
private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;
}

private void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] utak = (string[])e.Data.GetData(DataFormats.FileDrop);

if (utak.Length > 0)
{
Megnyit(utak[0]);
}
}

6. Biztonságos mentés ideiglenes fájllal

A mentés közben a program összeomlik: a fájl részben íródhat, és az eredeti elvész. Hogyan védekezel ideiglenes fájllal és átnevezéssel?

Megoldás megnyitása

Előbb egy ideiglenes fájlba írsz, és csak siker esetén cseréled az eredetit (File.Replace vagy File.Move törlés után). Így az eredeti sosem marad félkész állapotban.

Form1.csC#
private void BiztonsagosMent(string ut, string tartalom)
{
string ideiglenes = ut + ".tmp";

File.WriteAllText(ideiglenes, tartalom);

if (File.Exists(ut))
{
File.Delete(ut);
}

File.Move(ideiglenes, ut);
}

Gyors önellenőrzés

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

1. Hogyan épül fel a Filter szöveg?

Felirat|minta párokban, | jellel elválasztva; a több minta pontosvesszővel.

2. Honnan számozódik a FilterIndex?

1-től.

3. Mit ad a FileNames?

Multiselect esetén az összes kiválasztott fájl útvonalát.

4. Mire való a DefaultExt?

A kiterjesztést automatikusan hozzáfűzi a mentett fájlnévhez, ha a felhasználó nem ad meg.

5. Hová mentsd a felhasználói adatokat?

A felhasználó mappáiba (MyDocuments, ApplicationData), nem a program mappájába.

6. Mik a leggyakoribb fájl-kivételek?

FileNotFoundException, UnauthorizedAccessException, IOException, ArgumentException.

7. Miért nem elég a File.Exists?

A vizsgálat után a fájl még törlődhet vagy lezárulhat: a try–catch kell.

Mit tudsz már?

  • Szűrőt építesz, és az OpenFileDialog, SaveFileDialog, FolderBrowserDialog beállításait ismered.
  • Többes kijelölést és felülírás-védelmet használsz.
  • Megjegyzed az utolsó mappát, és a különleges mappákat használod.
  • A fájladatokat a FileInfo osztállyal olvasod.
  • Érthetően kezeled a fájl- és mappahibákat.

Következő lecke: FontDialog és ColorDialog

A betűtípus- és színválasztó ablakok: alkalmazás a kijelölésre és az egész szövegre, mentés szövegként, és a kontraszt ellenőrzése.