1. Giriş
Fayllarla işləyərkən bəzən (bəzən çox da sirli olan) xətalarla üzləşdiyimiz neqativ situasiyaları müzakirə etməyin vaxtıdır. Əgər əvvəllər System.Text.DecoderFallbackException kimi xətalarla rastlaşmısınızsa, bu mövzu ilə tanışsınız!
Bu mühazirədə nəyi nəzərdən keçirəcəyik:
- .NET-də kodlaşdırma ilə bağlı hansı xətalar olur;
- Zədələnmiş və ya səhv fayllar necə özünü göstərir;
- Belə xətaların ələ alınması və işlənməsi üzrə praktik nümunələr;
- Müxtəlif mənbələrdən gələn (və ya “köhnə” disklərdən tapılan) fayllarla işləyərkən nələrə diqqət etmək lazımdır.
Beləliklə, əgər ASCII çox sadə, Unicode isə çox “ağıllı”dırsa, bəzən fayllar olur ki, heç kim oxuya bilmir. Elə bu zaman istisnalar ortaya çıxır.
Niyə belə olur?
Faylı StreamReader ilə açdığınız zaman, kodlaşdırmanı göstərəndə (və ya default istifadə edəndə), .NET bütün baytların düzgün simvollara çevriləcəyini hesab edir. Amma faylda həmin kodlaşdırmaya uyğun olmayan baytlar olsa, dekodlaşdırma xətası yaranır.
2. Yanlış kodlaşdırma ilə faylları oxuyarkən olan istisnalar
Ən yayılmış istisna — DecoderFallbackException
Bu istisna .NET tərəfindən gözlənən kodlaşdırmada bayt ardıcıllığını simvola uyğun gətirmək mümkün olmadıqda atılır.
Sadə nümunə, hər şey aydın olsun deyə:
// Gəlin, köhnə Windows-1251 (kirilitsa) faylı olsun
string win1251File = "win1251_test.txt";
File.WriteAllText(win1251File, "Privet, mir!", Encoding.GetEncoding("windows-1251"));
try
{
// Bu faylı UTF-8 kimi oxumağa çalışaq
using var reader = new StreamReader(win1251File, Encoding.UTF8);
string content = reader.ReadToEnd();
Console.WriteLine(content); // ...və ekranda qarışıq simvollar (və ya istisna) görünə bilər
}
catch (DecoderFallbackException ex)
{
Console.WriteLine("Dekodlaşdırma xətası: " + ex.Message);
}
Çox vaxt Windows-1251-də saxlanmış faylı UTF-8 kimi oxuyanda məna verən mətn əvəzinə “qarışıq simvollar” alınır. Default olaraq StreamReader belə hallarda istisna atmır, əvəzinə naməlum baytların yerinə əvəzetmə simvolu "�" qoyur. Amma əgər kodlaşdırmanı sərt DecoderExceptionFallback ilə konfiqurasiya etmisinizsə və ya axında çox “qəbulolunmaz” baytlar varsa, DecoderFallbackException atıla bilər.
DecoderFallbackException ətraflı
- Nə vaxt yaranır: cari kodlaşdırmada baytlar simvollara çevrilə bilmədikdə.
- Nə etmək lazımdır: faylı düzgün kodlaşdırma ilə oxuyun! Faylın hansı kodlaşdırmada olduğunu bilmirsinizsə, BOM və ya fayl adından təxmin etməyə çalışın və ya faylı yaradanla məsləhətləşin.
3. Aydındır ki, fayl əslində zədələnibsə — nümunə
İndi işi bir az çətinləşdirək. Tutaq ki, fayl zədələnib: bayt ardıcıllığında yarımçıq simvol parçaları var. Belə şeylər yazı prosesi yarımçıq qalanda, şəbəkə xətalarında, uğursuz konversiyalarda və ya sadəcə fayl “kəsildikdə” baş verir.
“Zədəli” fayl yaradaq
// UTF-8 ilə düzgün sətir yazırıq
byte[] valid = Encoding.UTF8.GetBytes("Privet, mir!");
// İndi isə bayt massivini səhv yaradıb (bir baytı kəsirik)
byte[] corrupted = new byte[valid.Length - 1];
Array.Copy(valid, corrupted, valid.Length - 1); // Sonuncu baytı kəsdik
// Faylı saxlayırıq
File.WriteAllBytes("corrupted.txt", corrupted);
try
{
using var reader = new StreamReader("corrupted.txt", Encoding.UTF8);
string s = reader.ReadToEnd();
Console.WriteLine("Oxunan mətn: " + s);
}
catch (DecoderFallbackException ex)
{
Console.WriteLine("Fayl zədələnib! " + ex.Message);
}
Nəticə: .NET son simvolu düzgün şəkildə yığa bilməyəcək. Default halda onu xüsusi əvəzetmə simvolu "�" (və ya "?") ilə əvəz edəcək, amma əgər kodlaşdırma uyğun şəkildə konfiqurasiya edilibsə, DecoderFallbackException atıla bilər.
4. Fallback-strategiyalar: istisnadan necə qaçmaq olar?
Bəzən simvol “naməlum” olduqda, xətanı atmamağı və əvəzinə onu məsələn “?” ilə əvəz etməyi istəyirsən. .NET-də buna uyğun müxtəlif fallback strategiyaları var.
Nümunə: xətanın atılmasını simvol ilə əvəz etməklə əvəz edək
// UTF-8 üçün düzgün olmayan ardıcıllıq massiv
byte[] data = { 0xD0, 0x9F, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5, 0xD1, 0x82, 0xD1 }; // Sonuncu bayt kəsilib
File.WriteAllBytes("broken_utf8.txt", data);
// Fallback-strategiya: problemli simvolu sual işarəsi ilə əvəz et
var encodingWithFallback = Encoding.GetEncoding(
"UTF-8",
new EncoderReplacementFallback("?"),
new DecoderReplacementFallback("?")
);
using var reader = new StreamReader("broken_utf8.txt", encodingWithFallback);
string s = reader.ReadToEnd();
Console.WriteLine("Mətn (xətalar əvəz olundu): " + s);
Nəticə: fayldan oxunan mətndə naməlum simvollar "?" ilə əvəz olunacaq. Beləliklə proqramın çöküşünün qarşısını alırsınız, amma mətn tam orijinal olmayacaq.
5. BOM və qeyri-uyğunluqla bağlı problemlər
Xatırladaq ki, BOM — Byte Order Markdır, faylın başlanğıcındakı xüsusi bayt ardıcıllığıdır, hansı ki “salam, mən belə kodlaşdırmaam!” deyir.
BOM nə vaxt başağrısı yarada bilər
- Əgər faylda BOM var, amma tətbiq onu düzgün oxumur, onda ilk simvol qəribə görünə bilər (məsələn, "" və ya görünməyən simvol).
- Bəzən BOM-un olmaması kodlaşdırmanın səhv təyin edilməsinə səbəb olur.
BOM ilə bağlı istisnalar
Adətən C# BOM-u oxumağı bacarır, amma yanlış kodlaşdırma göstərsəniz və ya BOM-u əllə kəsərsinizsə, risk var ki:
- Başlanğıcda gözlənilməz simvol görəcəksiniz (məsələn, "�");
- Əgər kodlaşdırma onu xətalı ardıcıllıq sayarsa, istisna atıla bilər.
Praktik məsləhət: oxumaq/yazmaq zamanı kodlaşdırmanı açıq şəkildə göstərin, əgər onun tipi sizin üçün vacibdirsə.
6. Digər maraqlı istisnalar və ssenarilər
Yazarkən səhv kodlaşdırma seçilməsi
Məsələn, seçilmiş kodlaşdırma dəstəkləmədiyi simvolları ehtiva edən sətiri yazmağa çalışanda. Məsələn, “😊” smaylını Encoding.ASCII ilə saxlamağa çalışın:
try
{
using var writer = new StreamWriter("ascii.txt", false, Encoding.ASCII);
writer.WriteLine("Bu bir test 😊");
}
catch (EncoderFallbackException ex)
{
Console.WriteLine("Kodlaşdırma xətası: " + ex.Message);
}
Nəticə: ya EncoderFallbackException alacaqsınız, ya da həmin simvol "?" ilə əvəz olunacaq — hansı fallback strategiyasının seçilməsindən asılıdır.
Kodlaşdırmalar arasında konvertasiya problemi (məlumat itkisi)
Faylı konvertasiya edərkən əgər target kodlaşdırmada source-dakı bütün simvollar yoxdursa, məlumat itkisi ola bilər (məsələn, UTF-8-dən Windows-1251-ə konvertasiya edərkən yapon mətnini itirə bilərsiniz).
Disk, şəbəkə və ya “əl ilə redaktə” nəticəsində faylın zədələnməsi
Əgər fayla təsadüfi və ya zədələnmiş baytlar düşübsə (məsələn, disk xətası və ya binary faylı mətn redaktorunda açmaq), belə faylı oxumaq cəhdləri çox vaxt dekodlaşdırma istisnaları ilə nəticələnir.
7. Praktikada xətaları necə ələ almaq və işləmək?
Xətalar fayllarla işin müxtəlif mərhələlərində ortaya çıxa bildiyi üçün tövsiyə olunur:
- try-catch bloklarından istifadə edin və əsasən DecoderFallbackException və EncoderFallbackException tutun.
- İstifadəçini məlumatlandırmaqdan çəkinməyin: fayl zədələnibsə və ya kodlaşdırma yanlışsa, bunu demək daha yaxşıdır, tərs halda qəribə mətn göstərə bilərsiniz.
- Mümkünsə kodlaşdırmanı avtomatik müəyyənləşdirin (məsələn, BOM və ya Ude kimi kitabxanalar ilə), amma uğursuzluq olduqda həmişə istifadəçiyə seçim vermək yaxşıdır.
Tipik kod strukturu:
try
{
using var reader = new StreamReader("file.txt", Encoding.GetEncoding("windows-1251"));
string s = reader.ReadToEnd();
Console.WriteLine(s);
}
catch (DecoderFallbackException ex)
{
Console.WriteLine($"Faylı oxumaq mümkün olmadı: {ex.Message}");
// İstifadəçiyə başqa kodlaşdırmanı sınamağı təklif etmək olar
}
catch (IOException ex)
{
Console.WriteLine($"I/O xətası: {ex.Message}");
}
8. Bir neçə "tipik xətalar" haqda
UTF-8 faylı Windows-1251 ilə oxumağa çalışmağa cəhd: ən yaxşı halda “qarışıq simvollar”, ən pis halda isə istisna (əgər kodlaşdırma onu atacaq şəkildə qurulubsa).
Rus mətnli faylı ASCII ilə yazmaq: İngilis əlifbası olmayan hər şey "?" ilə əvəz olunacaq və ya EncoderFallbackException yaranacaq.
BOM olmayan faylı UTF-8 kimi oxumaq, əgər əslində fayl UTF-16-dır: qarışıq simvollar oxunacaq və bəzən faylı ümumiyyətlə oxumaq mümkün olmayacaq.
Qeyri-müəyyən kodlaşdırmalı mənbələrdən gələn fayllar: həmişə ehtiyatlı olun: fayl “səhvsiz” açılanda belə, nəticənin düzgün olacağının təminatı yoxdur.
GO TO FULL VERSION