Grafikus C# – Windows Forms tanfolyam › 10.3 lecke

Windows Forms · 10.3 lecke · kódolás

Szövegfájlok és UTF-8 kódolás

Egy fájlban nincsenek betűk: csak bájtok (0–255 közötti számok). Hogy a ő, ű, á melyik bájt-sorozatot jelenti, azt a kódolás (encoding) dönti el. Ha a fájlt író és az olvasó program más kódolást feltételez, a szöveg tönkremegy: körte, õ az ő helyett, ? jelek. Magyar nyelvű programban ez a legsűrűbb szövegfájl-hiba. Ebben a leckében megérted a bájt és karakter viszonyát, az UTF-8, UTF-16 és Windows-1250 különbségét, a BOM szerepét, a sorvégeket, és hogyan olvasol, írsz és alakítasz át szövegeket biztonságosan.

  • kb. 100 perc
  • közepes szint
  • kódolás
Diáklány C# programot készít laptopon

A lecke végére

  • magyarázod, mi a különbség a bájt, a karakter és a kódolás között;
  • ismered az UTF-8, UTF-16, Windows-1250 és ISO-8859-2 kódolást, és tudod, melyiket mikor használd;
  • érted a BOM jelentését, és megadod a kódolást olvasáskor és íráskor (Encoding);
  • felismered a kódolási hibák tüneteit (ö, õ, ?), és az okukat;
  • a Windows-1250 kódolást is eléred (CodePagesEncodingProvider);
  • kezeled a sorvégeket (\r\n és \n), és átalakítasz egy fájlt másik kódolásra, veszteség-ellenőrzéssel.

Mielőtt elkezded

Ehhez a leckéhez a 10.1–10.2 lecke (File, StreamReader, StreamWriter) és a 3.3 lecke (char, string) szükséges.

10.2 Adatfolyamok →

Bájt, karakter és kódolás

A string karakterekből áll (a memóriában UTF-16). A fájlba bájtok kerülnek: a kódolás a karakter → bájtok megfeleltetés. Ugyanaz a szöveg különböző kódolással különböző bájtokat ad:

Form1.cs (using System.Text;)C#
string szoveg = "őrült";

byte[] utf8 = Encoding.UTF8.GetBytes(szoveg);
byte[] utf16 = Encoding.Unicode.GetBytes(szoveg);

// kiírás hexadecimálisan: BitConverter.ToString(utf8)
// UTF-8: C5-91-72-C3-BC-6C-74 (az ő két bájt: C5 91, az ü két bájt: C3 BC)
// UTF-16: 51-01-72-00-FC-00-6C-00-74-00 (minden karakter 2 bájt, kisvégű)

// vissza: ugyanazt a kódolást kell használni!
string jo = Encoding.UTF8.GetString(utf8); // őrült
string rossz = Encoding.Latin1.GetString(utf8); // körte típusú hiba: Å‘rült
KódolásJellemzőMikor?
UTF-8Változó hosszúságú (1–4 bájt); az ASCII karakterek 1 bájtosak; minden nyelv betűit tudja.Az alapértelmezett választás: weben, JSON-ban, XML-ben, új fájlokban.
UTF-16 (Encoding.Unicode)Karakterenként 2 (vagy 4) bájt.Windows belső szövegábrázolása; néhány régi Windows-fájl (Jegyzettömb „Unicode”).
Windows-12501 bájt/karakter, közép-európai betűk (ő, ű is).Régi magyar Windows-programok fájljai, régi CSV-k.
ISO-8859-2 (Latin-2)1 bájt/karakter, közép-európai; kismértékben eltér a Windows-1250-től.Régi Unix/web tartalmak.
ASCII7 bit: csak angol betűk és jelek.Ékezetes betűket NEM tud: ? lesz belőlük.
A kódolás nincs a fájlbanA fájl nem mondja meg, milyen kódolású (kivéve a BOM jelzést, lásd lent). A beolvasó program kitalálja vagy a felhasználótól kapja. Ezért kell az olvasáskor megadni.
UnicodeA Unicode a karakterek nemzetközi számozása (kódpontok); az UTF-8, UTF-16 ennek a különböző bájt-ábrázolásai. A Unicode minden írásrendszert tartalmaz (magyar, kínai, emoji).
Karakter ≠ bájtAz ő UTF-8-ban 2 bájt. A fájl mérete bájtban ezért nagyobb lehet, mint a karakterek száma. A string.Length a UTF-16 egységeket számolja (az emoji 2 egység).
Latin1 az ő-hoz?A nyugat-európai (Latin-1, Windows-1252) kódolás az ő-t és ű-t nem tartalmazza: ezért lesz belőlük õ és û (a tilde és a circumflex változatok). Ez a legismertebb magyar kódolási hiba.

Jósolj!

A program File.WriteAllText(ut, "őrült", Encoding.ASCII) módon ment. Mi lesz a fájl tartalma?

Jóslat ellenőrzése

?r?lt (kérdőjelek az ő és ü helyén): az ASCII nem tudja ábrázolni az ékezetes betűket, és csendben ? karakterre cseréli őket. Az információ visszaállíthatatlanul elveszik: ASCII kódolásba ékezetes szöveget soha ne ments.

UTF-8, BOM és a .NET alapértelmezései

A BOM (byte order mark) a fájl elején álló néhány bájt, amely a kódolást jelzi: UTF-8 esetén EF BB BF, UTF-16 esetén FF FE. Egyes programok (régebbi Jegyzettömb, Excel) a BOM alapján ismerik fel az UTF-8-at. A .NET alapértelmezései:

Form1.csC#
// ÍRÁS: a File.WriteAllText és a StreamWriter alapértelmezése UTF-8 BOM NÉLKÜL
File.WriteAllText(ut, szoveg);

// kifejezetten BOM-mal (az Excel és a régi programok így ismerik fel az UTF-8-at)
File.WriteAllText(ut, szoveg, new UTF8Encoding(true));

// OLVASÁS: a StreamReader felismeri a BOM-ot, és annak megfelelően dekódol;
// BOM nélkül UTF-8-nak veszi (ezért a Windows-1250 fájl ékezetei elromlanak!)
using (StreamReader olvaso = new StreamReader(ut))
{
string tartalom = olvaso.ReadToEnd();
Encoding felismert = olvaso.CurrentEncoding; // a ReadToEnd után a ténylegesen használt kódolás
}

// konkrét kódolás megadása olvasáskor
string szoveg2 = File.ReadAllText(ut, Encoding.Unicode);

// a fájl első bájtjai: BOM felismerése kézzel
byte[] fej = new byte[3];

using (FileStream fs = new FileStream(ut, FileMode.Open, FileAccess.Read))
{
int db = fs.Read(fej, 0, 3);

bool utf8Bom = db == 3 && fej[0] == 0xEF && fej[1] == 0xBB && fej[2] == 0xBF;
bool utf16Bom = db >= 2 && fej[0] == 0xFF && fej[1] == 0xFE;
}
BOM-os vagy BOM nélküli?A BOM nélküli UTF-8 a modern szabvány (web, JSON, Linux). A BOM-ot az Excel igényli, ha az UTF-8 CSV-t ékezetesen akarod megnyitni (10.5 lecke). Szabályként: új fájl UTF-8, BOM csak ha a fogadó program kéri.
Az olvasás nem tévedhetetlenA StreamReader a BOM-ból tud felismerni. BOM nélküli Windows-1250 fájlt UTF-8-nak hisz, és az ékezetes betűk helyén ismeretlen karakter (�) jelenik meg. A kódolást ilyenkor a felhasználó kiválaszthatja, vagy a program tippel.
Helyettesítő karakterA � (U+FFFD) azt jelzi, hogy a bájt-sorozat nem érvényes az adott kódolásban. Ha ilyet látsz a beolvasott szövegben, rossz kódolással olvastál.
Utf8 vagy Default?Az Encoding.Default a .NET Framework alatt a gép ANSI kódlapja (magyar Windows-on Windows-1250), újabb .NET-ben UTF-8: a viselkedése verziófüggő, ezért kerüld; mindig nevezd meg a kódolást.

Jósolj!

Az Excel egy BOM nélküli UTF-8 CSV-fájlt nyit meg a magyar Windowson, kettős kattintással. Mit lát a felhasználó az ő és ű betűk helyén?

Jóslat ellenőrzése

Értelmetlen karakterpárokat, például Å‘ az ő helyén: a BOM hiányában az Excel a gép ANSI kódolásával (Windows-1250) olvassa az UTF-8 bájtokat. BOM-mal (new UTF8Encoding(true)) a fájl helyesen jelenik meg.

Windows-1250 és Latin-2 olvasása

Régi magyar programok (és sok CSV-export) Windows-1250 kódolású fájlt írnak. Az újabb .NET (Core, 5+) alapból csak néhány kódolást ismer: a többit (köztük a Windows-1250-et) a CodePagesEncodingProvider teszi elérhetővé (a .NET Framework alatt nem kell, és a regisztráció ártalmatlan):

Program.cs vagy Form1.cs (using System.Text;)C#
// egyszer, a program indulásakor (például a Main metódus elején)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding win1250 = Encoding.GetEncoding(1250); // vagy GetEncoding("windows-1250")
Encoding latin2 = Encoding.GetEncoding("iso-8859-2");

string szoveg = File.ReadAllText(regiFajl, win1250);
File.WriteAllText(ujFajl, szoveg, new UTF8Encoding(false)); // átalakítás UTF-8-ra

// veszteség-ellenőrzés: kivételt dob, ha a szöveg nem ábrázolható a célkódolásban
Encoding szigoru = Encoding.GetEncoding("iso-8859-2", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);

try
{
byte[] bajtok = szigoru.GetBytes("Árvíztűrő tükörfúrógép ✓"); // a ✓ nincs a Latin-2-ben
}
catch (EncoderFallbackException ex)
{
lblHiba.Text = "Nem ábrázolható karakter: " + ex.CharUnknown; // a konvertálás előtt figyelmeztetünk
}
RegisterProviderA CodePagesEncodingProvider a System.Text.Encoding.CodePages csomagban van (újabb .NET-ben beépített). Nélküle a GetEncoding(1250) ArgumentException kivételt dob. A regisztráció egyszeri.
Windows-1250 vagy Latin-2?Mindkettő közép-európai, de az ő és ű kódja azonos, néhány más karakter (például a Š környéke) más. Magyar szövegnél gyakran mindkettő jól jelenik meg, a pontos kódolást a forrás határozza meg. Windows programoknál a 1250, Unixnál a Latin-2 a valószínű.
Veszteséges átalakításA célkódolás alapértelmezetten a nem ábrázolható karaktert ?-re cseréli, csendben. A ExceptionFallback hibát jelez: így figyelmeztethetsz, mielőtt az adat elvész. UTF-8-ba alakítás sosem veszteséges.
Tipp a kódolásraA kódolás hibátlanul nem fedezhető fel; a gyakorlatban: (1) BOM, (2) érvényes UTF-8-e (DecoderFallback.ExceptionFallback nem dob), (3) különben a gép ANSI kódolása (Windows-1250). A felhasználó mindig kijavíthatja.

Jósolj!

Egy Windows-1250 fájlban az ő betű a F5 bájt. A program UTF-8-ként olvassa a fájlt (ReadAllText(ut)). Mit jelenít meg?

Jóslat ellenőrzése

Egy � (helyettesítő karaktert): az F5 bájt önmagában nem érvényes UTF-8 (a többbájtos karakter első bájtja, de nincs folytatása). A beolvasott szöveg „sérült”, a hiba felismerhető a � karakterekről.

Sorvégek

A sor végét a Windows két karakterrel jelzi (\r\n, CRLF), a Linux és a Mac egyel (\n, LF). A StreamReader.ReadLine és a File.ReadAllLines mindkettőt jól kezeli. Gond akkor van, ha a szöveget kézzel bontod (Split('\n'): a \r a sor végén marad), vagy a TextBox.Text és a fájl sorvégei keverednek:

Form1.csC#
// jó: mindkét sorvéget kezeli
string[] sorok = File.ReadAllLines(ut);

// hibás: az \r a sor végén marad, ha a fájl CRLF
string[] rossz = tartalom.Split('\n');

// helyes kézi bontás
string[] jo = tartalom.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);

// egységesítés a rendszer sorvégére
string egyseges = tartalom.Replace("\r\n", "\n").Replace("\n", Environment.NewLine);

// kiíráskor: Environment.NewLine (Windows alatt CRLF)
File.WriteAllText(ut, "egy" + Environment.NewLine + "kettő");

Jósolj!

A fájlt Windows-on írták (CRLF), és a program tartalom.Split('\n') hívással bontja sorokra, majd sor == "alma" módon hasonlít. Egyezik-e az első sor?

Jóslat ellenőrzése

Nem: a sor "alma\r" (a CR karakter ott marad). A hasonlítás hamis, a hiba nehezen látható. A ReadAllLines és a ReadLine a CRLF-et jól kezeli, vagy Trim() és a kétféle sorvég szerinti Split kell.

📷 Képernyőkép helye

Mit tegyél ide: a kódolás-átalakító: a bal oldalon a rossz kódolással beolvasott szöveg (Å‘), a jobb oldalon a helyes, alatta a hexadecimális nézet és a BOM jelzése.Javasolt fájlnév: winforms-10-3-kodolas.webp · Alt szöveg: A kódolás-átalakító 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. Az ő és ű betűk helyén � jelek

Egy régi program fájlját olvasod be.

Ok és javítás

A fájl valószínűleg Windows-1250, a program UTF-8-ként olvassa. Add meg a kódolást (Encoding.GetEncoding(1250), előbb RegisterProvider), vagy kínálj a felhasználónak kódolás-választót.

2. ArgumentException a GetEncoding(1250) hívásnál

Encoding e = Encoding.GetEncoding(1250);   // újabb .NET-ben regisztráció nélkül kivétel
Hiba és javítás

Előbb: Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); (egyszer, induláskor).

3. Az Excel értelmetlen betűket mutat

A program UTF-8 CSV-t ment, az Excelben az ékezetek hibásak.

Ok és javítás

BOM nélküli UTF-8: az Excel ANSI kódolásúnak veszi. Mentsd new UTF8Encoding(true) (BOM-os UTF-8) kódolással.

4. Az ékezetes betűk kérdőjellé váltak a mentett fájlban

File.WriteAllText(ut, szoveg, Encoding.ASCII);
Hiba és javítás

Az ASCII nem tud ékezetes betűt: ? lesz belőlük, az adat elveszik. Használj UTF-8-at.

5. A sor végén láthatatlan karakter

A beolvasott szöveg hasonlítása nem egyezik, bár a szöveg azonosnak látszik.

Ok és javítás

CRLF fájl Split('\n') bontásnál: a \r marad. Használj ReadAllLines metódust, vagy Trim()-et.

6. A fájl két kódolás keveréke

A fájl egyik fele helyes, a másik hibás.

Ok és javítás

Több program írt bele eltérő kódolással (például egy hozzáfűzés más kódolással). Az egy fájlba írt részek ugyanazt a kódolást használják: a StreamWriter(ut, true, Encoding.UTF8) kódolását is add meg hozzáfűzéskor.

Mini projekt: kódolás-átalakító

Készíts programot, amely szövegfájlt nyit meg több kódolással, mutatja a bájtokat, és átalakítja:

  1. Felület: Megnyitás..., cmbKodolas (UTF-8, UTF-16, Windows-1250, ISO-8859-2, ASCII, Windows-1252), Automatikus jelölő; txtSzoveg (az eredmény), txtHex (az első 64 bájt hexadecimálisan, csak olvasható); lblInfo; Mentés másként..., cmbCel (cél kódolás), chkBom (BOM), cmbSorveg (Windows (CRLF), Unix (LF)).
  2. Regisztráció: a program elején Encoding.RegisterProvider(CodePagesEncodingProvider.Instance).
  3. Automatikus felismerés: (1) BOM (UTF-8, UTF-16 LE/BE); (2) érvényes UTF-8-e (ExceptionFallback dekódolóval); (3) különben Windows-1250. A felismert kódolás a legördülőben beállítódik, és az lblInfo megmondja az okot (BOM alapján / érvényes UTF-8 / feltételezés).
  4. Beolvasás: a fájl bájtjai (File.ReadAllBytes), a kijelölt kódolással dekódolva (a BOM bájtjait nem kell a szövegben mutatni); a � karakterek száma jelzi a gyanús kódolást (lblInfo: 3 ismeretlen karakter: valószínűleg más a kódolás).
  5. Hexadecimális nézet: az első 64 bájt 16-os sorokban (BitConverter.ToString), a BOM kiemelve szövegben (UTF-8 BOM (EF BB BF)).
  6. Átalakítás és mentés: a cél kódolás és a BOM választható; a sorvég egységesítve; veszteség-ellenőrzés (ExceptionFallback): ha a szöveg nem ábrázolható a célban, a program felsorolja az első néhány problémás karaktert, és megkérdezi, folytassa-e (? cserével); a mentés új fájlba (az eredeti nem íródik felül).
  7. Hibatűrés: üres fájl, bináris fájl (sok �), nagy fájl (> 20 MB figyelmeztetés), zárolt fájl; a program nem omlik össze.
  8. Teszteld: egy UTF-8 BOM-mal, UTF-8 BOM nélkül, Windows-1250 és UTF-16 fájllal (a Jegyzettömb Mentés másként ablakában választható a kódolás); az Árvíztűrő tükörfúrógép mondat mindegyikben; ASCII-ra átalakítás figyelmeztetése; CRLF és LF sorvég.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A központi rész a Felismer metódus (BOM → érvényes UTF-8 → feltételezés) és a veszteség-ellenőrzéses mentés.

Form1.cs (using System.Text; using System.IO; using System.Linq;)C#
private byte[] bajtok = new byte[0];

private void Form1_Load(object sender, EventArgs e)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

string[] nevek = { "UTF-8", "UTF-16 (LE)", "Windows-1250", "ISO-8859-2", "ASCII", "Windows-1252" };

cmbKodolas.Items.AddRange(nevek);
cmbCel.Items.AddRange(nevek);
cmbKodolas.SelectedIndex = 0;
cmbCel.SelectedIndex = 0;
cmbSorveg.Items.AddRange(new object[] { "Windows (CRLF)", "Unix (LF)" });
cmbSorveg.SelectedIndex = 0;
}

private Encoding KodolasBol(int index, bool szigoru)
{
Encoding e;

switch (index)
{
case 1: e = Encoding.Unicode; break;
case 2: e = Encoding.GetEncoding(1250, szigoru ? EncoderFallback.ExceptionFallback : EncoderFallback.ReplacementFallback, szigoru ? DecoderFallback.ExceptionFallback : DecoderFallback.ReplacementFallback); break;
case 3: e = Encoding.GetEncoding("iso-8859-2", szigoru ? EncoderFallback.ExceptionFallback : EncoderFallback.ReplacementFallback, szigoru ? DecoderFallback.ExceptionFallback : DecoderFallback.ReplacementFallback); break;
case 4: e = Encoding.GetEncoding("us-ascii", szigoru ? EncoderFallback.ExceptionFallback : EncoderFallback.ReplacementFallback, szigoru ? DecoderFallback.ExceptionFallback : DecoderFallback.ReplacementFallback); break;
case 5: e = Encoding.GetEncoding(1252, szigoru ? EncoderFallback.ExceptionFallback : EncoderFallback.ReplacementFallback, szigoru ? DecoderFallback.ExceptionFallback : DecoderFallback.ReplacementFallback); break;
default: e = szigoru ? new UTF8Encoding(false, true) : new UTF8Encoding(false); break; // a második paraméter: hibát dob érvénytelen bájtra
}

return e;
}

// BOM → érvényes UTF-8 → feltételezés (Windows-1250)
private int Felismer(byte[] b, out string ok)
{
if (b.Length >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF) { ok = "BOM alapján (UTF-8)"; return 0; }
if (b.Length >= 2 && b[0] == 0xFF && b[1] == 0xFE) { ok = "BOM alapján (UTF-16 LE)"; return 1; }

try
{
new UTF8Encoding(false, true).GetString(b); // kivételt dob, ha érvénytelen
ok = "érvényes UTF-8 bájtsorozat";
return 0;
}
catch (DecoderFallbackException)
{
ok = "nem érvényes UTF-8, feltételezés: Windows-1250";
return 2;
}
}

private string Dekodol(byte[] b, Encoding kod)
{
int kezd = 0;

// a BOM bájtjait nem mutatjuk a szövegben
if (kod.CodePage == 65001 && b.Length >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF) { kezd = 3; }
else if (kod.CodePage == 1200 && b.Length >= 2 && b[0] == 0xFF && b[1] == 0xFE) { kezd = 2; }

return kod.GetString(b, kezd, b.Length - kezd);
}

private void Mutat()
{
if (bajtok.Length == 0) { return; }

string szoveg = Dekodol(bajtok, KodolasBol(cmbKodolas.SelectedIndex, false));

txtSzoveg.Text = szoveg.Replace("\r\n", "\n").Replace("\n", Environment.NewLine);

int ismeretlen = szoveg.Count(c => c == '\uFFFD');

lblInfo.Text = bajtok.Length + " bájt, " + szoveg.Length + " karakter" + (ismeretlen > 0 ? ", " + ismeretlen + " ismeretlen karakter: valószínűleg más a kódolás" : "");

// hexadecimális nézet: 16 bájt soronként
StringBuilder sb = new StringBuilder();
int db = Math.Min(64, bajtok.Length);

for (int i = 0; i < db; i += 16)
{
sb.AppendLine(BitConverter.ToString(bajtok, i, Math.Min(16, db - i)).Replace('-', ' '));
}

if (bajtok.Length >= 3 && bajtok[0] == 0xEF && bajtok[1] == 0xBB && bajtok[2] == 0xBF) { sb.AppendLine("(UTF-8 BOM: EF BB BF)"); }

txtHex.Text = sb.ToString();
}

private void btnMegnyit_Click(object sender, EventArgs e)
{
if (ofd.ShowDialog(this) != DialogResult.OK) { return; }

try
{
if (new FileInfo(ofd.FileName).Length > 20 * 1024 * 1024 && MessageBox.Show(this, "A fájl nagyobb 20 MB-nál. Betöltsem?", "Nagy fájl", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != DialogResult.Yes) { return; }

bajtok = File.ReadAllBytes(ofd.FileName);
}
catch (IOException ex) { MessageBox.Show(this, "A fájl nem olvasható: " + ex.Message, "Megnyitás", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }
catch (UnauthorizedAccessException) { MessageBox.Show(this, "Nincs jogosultság a fájlhoz.", "Megnyitás", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }

if (chkAuto.Checked)
{
string ok;

cmbKodolas.SelectedIndex = Felismer(bajtok, out ok);
tsslUzenet.Text = "Felismerés: " + ok;
}

Mutat();
}

private void cmbKodolas_SelectedIndexChanged(object sender, EventArgs e) { Mutat(); }

private void btnMent_Click(object sender, EventArgs e)
{
if (txtSzoveg.TextLength == 0) { return; }

string szoveg = txtSzoveg.Text.Replace("\r\n", "\n");

if (cmbSorveg.SelectedIndex == 0) { szoveg = szoveg.Replace("\n", "\r\n"); }

Encoding szigoru = KodolasBol(cmbCel.SelectedIndex, true);
byte[] ki;

try
{
ki = szigoru.GetBytes(szoveg);
}
catch (EncoderFallbackException ex)
{
if (MessageBox.Show(this, "Nem ábrázolható karakter a célkódolásban: '" + ex.CharUnknown + "'. Ezek ?-re cserélődnek. Folytatod?", "Veszteséges átalakítás", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes) { return; }

ki = KodolasBol(cmbCel.SelectedIndex, false).GetBytes(szoveg);
}

byte[] bom = chkBom.Checked ? KodolasBol(cmbCel.SelectedIndex, false).GetPreamble() : new byte[0]; // a BOM bájtjai (UTF-8: EF BB BF)

sfd.Filter = "Szöveg (*.txt)|*.txt|Minden fájl (*.*)|*.*";

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

try
{
File.WriteAllBytes(sfd.FileName, bom.Concat(ki).ToArray());
tsslUzenet.Text = "Mentve: " + Path.GetFileName(sfd.FileName);
}
catch (IOException ex) { MessageBox.Show(this, "A mentés nem sikerült: " + ex.Message, "Mentés", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}
📷 Képernyőkép helye

Mit tegyél ide: a kész kódolás-átalakító: a felismert kódolás, a szöveg és a hexadecimális nézet.Javasolt fájlnév: winforms-10-3-kesz.webp · Alt szöveg: A kész kódolás-átalakító

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. Bájtok száma

Hány bájt az Árvíztűrő szó UTF-8-ban, UTF-16-ban és Windows-1250-ben?

Egy lehetséges megoldás

A szóban 9 karakter van, ebből 4 ékezetes (Á, í, ű, ő). Az Encoding.GetByteCount megadja: UTF-8: 9 + 4 = 13 bájt, UTF-16: 18 bájt, Windows-1250: 9 bájt.

Form1.csC#
string s = "Árvíztűrő";int a = Encoding.UTF8.GetByteCount(s);int b = Encoding.Unicode.GetByteCount(s);int c = Encoding.GetEncoding(1250).GetByteCount(s);

2. Ékezet-mentesítés

Készíts függvényt, amely az ékezeteket eltávolítja (árvíztűrő → arvizturo), a kereséshez. Mit használsz?

Egy lehetséges megoldás

A string.Normalize(NormalizationForm.FormD) az ékezetes betűt alapbetűre és kombináló ékezetre bontja, a CharUnicodeInfo.GetUnicodeCategory pedig kiszűri az ékezeteket (NonSpacingMark).

Form1.cs (using System.Globalization;)C#
string Ekezetmentes(string s){    string bontott = s.Normalize(NormalizationForm.FormD);    StringBuilder sb = new StringBuilder();    foreach (char c in bontott)    {        if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) { sb.Append(c); }    }    return sb.ToString().Normalize(NormalizationForm.FormC);}

3. Tömeges átalakítás

Egy mappa összes .txt fájlját alakítsd UTF-8-ra, új almappába. Mire kell vigyáznod?

Egy lehetséges megoldás

Az eredetit ne írd felül; a kódolást fájlonként ismerd fel (BOM → UTF-8 érvényesség → feltételezés), és a bizonytalan fájlokat jelentsd; a hibás fájl ne állítsa le a teljes feldolgozást.

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. Mi az UTF-8 BOM?

Hány és milyen bájtok jelzik az UTF-8 BOM-ot?

Megoldás megnyitása

Három bájt: EF BB BF, a fájl elején.

2. Melyik kódolás?

Melyiket választod: (a) új JSON fájl; (b) régi magyar program importfájlja; (c) Excelben megnyitandó CSV?

Megoldás megnyitása

(a) UTF-8 BOM nélkül; (b) Windows-1250 (ha a program ezt várja); (c) UTF-8 BOM-mal.

Közepes szint

3. Az ismeretlen karakter

Hogyan számolod meg a beolvasott szövegben a � karaktereket, és mire jó?

Megoldás megnyitása

szoveg.Count(c => c == '\uFFFD'); ha nem nulla, a kódolás valószínűleg rossz: a program figyelmeztetheti a felhasználót, vagy másik kódolást próbálhat.

4. Hozzáfűzés más kódolású fájlhoz

A meglévő fájl Windows-1250, a program hozzáfűz. Mit kell tenned?

Megoldás megnyitása

A StreamWriter kódolását is Windows-1250-re állítod (new StreamWriter(ut, true, Encoding.GetEncoding(1250))); más kódolással a fájl két kódolás keveréke lenne.

Kihívás szint

5. Kódolás-tipp fájlrészletből

Készíts egyszerű tippelőt: a Windows-1250 szöveg gyakori betűit (é = E9, ő = F5) számolva döntsd el, jobban illik-e a fájl Latin-1-hez vagy a Windows-1250-hez. Mi a korlátja?

Megoldás megnyitása

Statisztikai tipp: a magyar szövegben az ő és ű (F5, FB a 1250-ben) gyakori, Latin-1-ben ezek õ és û. Rövid szövegnél megbízhatatlan; a végső szó mindig a felhasználóé (kódolás-választó).

6. UTF-8 érvényesség kézzel

Mikor érvénytelen egy bájt-sorozat UTF-8-ként? Adj két példát.

Megoldás megnyitása

(1) Egy 11xxxxxx kezdőbájt után hiányzik a 10xxxxxx folytatóbájt (például egyedül álló F5); (2) a folytatóbájt kezdőbájt nélkül áll. A .NET dekódoló ezeket � karakterre cseréli (vagy kivételt dob, ha kérsz).

Gyors önellenőrzés

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

1. Mi a kódolás?

A karakterek és a bájtok közötti megfeleltetés.

2. Miért az UTF-8 az alapértelmezett választás?

Minden nyelv betűit tudja, az ASCII-val kompatibilis, a web és a modern eszközök ezt használják.

3. Mire való a BOM?

A fájl elején jelzi a kódolást (például az Excel számára).

4. Mi a � jel?

Helyettesítő karakter: az érvénytelen bájt-sorozatot jelzi (rossz kódolással olvastál).

5. Miért kell RegisterProvider?

Az újabb .NET a Windows-1250-et csak a CodePagesEncodingProvider regisztrálása után ismeri.

6. Mi a baj az ASCII-val ékezetes szövegnél?

A nem ábrázolható karaktereket csendben ?-re cseréli: az adat elvész.

7. Miért veszélyes a Split('\n') CRLF fájlon?

A \r a sor végén marad, a hasonlítás hibás lesz.

Mit tudsz már?

  • Érted a bájt, karakter és kódolás viszonyát.
  • UTF-8-ban dolgozol, és tudod, mikor kell BOM.
  • Windows-1250 és Latin-2 fájlt is beolvasol, és felismered a kódolási hibák tüneteit.
  • Kezeled a sorvégeket.
  • Veszteség-ellenőrzéssel alakítasz át fájlt másik kódolásra.

Következő lecke: Fájl- és mappaválasztó párbeszédablakok

A 7.8 lecke mélyítése: segédosztály a fájlválasztáshoz, az utoljára használt mappa megjegyzése, útvonal-ellenőrzés és a legutóbbi fájlok listája.