CodeGym /Kurslar /C# SELF /Faylların təhlükəsiz oxunması və yazılması

Faylların təhlükəsiz oxunması və yazılması

C# SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Proqramlaşdırmada fayllarla təhlükəsiz işləmə dedikdə təkcə viruslardan və hakerlərdən qorunma yox, həm də düzgün xətaların, låklamanın, icazələrin, səhv yolların və digər gözlənilməz problemlərin idarə olunması nəzərdə tutulur. Laqeyd yanaşma məlumat itkisinə, proqramın donmasına, qəribə buglara və ya məşhur IOException istisnasına gətirib çıxara bilər.

Budur klassik situasiyalar, hansıları üzərində işləməyi öyrənməliyik:

  • Fayl mövcud deyil, amma biz onu oxumağa çalışırıq (və ya əksinə: fayl artıq yaradılıb, amma biz "yalnız yoxdursa yarat" rejimində yazmaq istəyirik).
  • Fayl başqa proqram tərəfindən açılıb və bloklanıb.
  • İstifadəçinin faylı və ya qovluğu oxuma/yazma icazəsi yoxdur.
  • Fayla aparan yol səhvlidir və ya qadağan olunmuş simvolları ehtiva edir.
  • Əməliyyat gözlənilmədən dayandırılıb (məsələn, disk dolub).
  • Pis praktika: açıq faylları qoymaq, axınları bağlamamaq.

Xoşbəxtlikdən, .NET bu problemləri həll etmək üçün bütün vasitələri verir. Onlar sadədir — amma təhlükəsizlik kəmərlərini taxmaq kimi, əsas məsələ onlardan istifadə etməkdir.

2. Fayllarla təhlükəsiz işin əsas prinsipləri

Faylın mövcudluğunu və icazələri əvvəlcədən yoxlayın

Faylı oxumazdan əvvəl onun mövcud olduğunu yoxlayın (məsələn, File.Exists vasitəsilə), xüsusən yol istifadəçidən gəlirsə:

string path = "test.txt";
if (!File.Exists(path))
{
    Console.WriteLine("Səhv: fayl tapılmadı.");
    return;
}

Yazmadan əvvəl qovluğun mövcudluğunu və yazmaq icazənizin olduğunu təsdiqləyin (və ya xətaları üst səviyyəyə atın).

Heç vaxt axınları açıq qoymayın

Axınların avtomatik bağlanması üçün using açar sözündən istifadə edin — bu ən yaxşı praktikadır:

using var writer = new StreamWriter("output.txt");
writer.WriteLine("Hello, files!");
// Burada fayl artıq bağlıdır, hətta səhv baş verərsə də!

Bu "donmuş" låklardan və resurs sızmalarından qoruyur.

Həmişə istisnaları tutun

Hər hansı fayl əməliyyatı istisna ata bilər. Fayl yeni olsa belə — onu çağıranda silinə və ya köçürülə bilər. try-catch konstruksiyasından istifadə edin:

try
{
    using var reader = new StreamReader("data.txt");
    string line = reader.ReadLine();
    Console.WriteLine(line);
}
catch (FileNotFoundException)
{
    Console.WriteLine("Fayl tapılmadı.");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Fayla giriş icazəsi yoxdur.");
}
catch (IOException ex)
{
    Console.WriteLine($"I/O xətası: {ex.Message}");
}

İstifadəçi inputuna inanmayın

Əgər fayl yolunu istifadəçi daxil edirsə, onu səhv yazma və ya proqramı qırmağa cəhd edə bilər. Path.GetInvalidPathChars() nəzərdən keçirmək tövsiyə olunur:

try
{
    string userPath = Console.ReadLine()!;
    if (string.IsNullOrWhiteSpace(userPath))
    {
        Console.WriteLine("Yol boş ola bilməz!");
        return;
    }
    // Əlavə: qadağan olunmuş simvolları yoxla
    foreach (char c in Path.GetInvalidPathChars())
        if (userPath.Contains(c))
        {
            Console.WriteLine("Yol qəbulagörənsiz simvollar ehtiva edir.");
            return;
        }
    // Bundan sonra faylla təhlükəsiz işləmək olar
}
catch (Exception ex)
{
    Console.WriteLine("Yolun validasiyasinda səhv: " + ex.Message);
}

3. Praktik nümunə: faylı "ciddi" oxuyuruq

Gəlin tədris layihəmizi bir az təkmilləşdirək. Tutaq ki, istifadəçinin daxil etdiyi adla faylı oxuyub məzmununu ekrana çıxarmalıyıq. Bütün bunlar — xətaların emalı və kodlaşdırma nəzərə alınmaqla.

Console.Write("Faylın yolunu daxil edin: ");
string? path = Console.ReadLine();

// Yolun validasiyası
if (string.IsNullOrWhiteSpace(path))
{
    Console.WriteLine("Yol boş ola bilməz!");
    return;
}
foreach (char c in Path.GetInvalidPathChars())
    if (path.Contains(c))
    {
        Console.WriteLine("Yol qəbulagörənsiz simvollar ehtiva edir.");
        return;
    }

// Faylı oxumağa çalışaq
try
{
    if (!File.Exists(path))
    {
        Console.WriteLine("Fayl tapılmadı.");
        return;
    }

    // Məsələn, UTF-8 kodlaşdırmasını açıq göstərək
    using var reader = new StreamReader(path, Encoding.UTF8);
    string content = reader.ReadToEnd();
    Console.WriteLine("Faylın məzmunu:");
    Console.WriteLine(content);
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Faylı oxumaq üçün icazə yoxdur.");
}
catch (IOException ex)
{
    Console.WriteLine("I/O xətası: " + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("Gözlənilməz xəta: " + ex.Message);
}

Qeyd edin ki, əgər fayl adını daxil etdikdən sonra fayl yoxa çıxsa, bu kod çökməyəcək: istisna tutularaq emal ediləcək. Axın using blokundan çıxdıqda avtomatik bağlanacaq — səhv olsa belə.

4. Yazma zamanı: məlumat itkisinə yol verməyin

Faylı yazarkən, xüsusilə overwrite rejimində (false ikinci parametr kimi StreamWriter konstruktorunda), təsadüfən vacib məlumatı silmək riski var. Bir neçə tövsiyə:

Mövcud faylı üst-üstə yazıb-yazmayacağınızı yoxlayın

Bəzən fayl artıq varsa istifadəçidən soruşmaq faydalıdır:

if (File.Exists(path))
{
    Console.WriteLine("Diqqət: fayl artıq mövcuddur. Üst-üstə yazılsın? (y/n)");
    string answer = Console.ReadLine()!;
    if (!answer.Equals("y", StringComparison.OrdinalIgnoreCase))
        return;
}

Yazma zamanı append rejimindən istifadə edin

using var writer = new StreamWriter("log.txt", append: true);
writer.WriteLine(DateTime.Now + ": yeni jurnal qeydi.");

Keçmiş məlumatlar itməyəcək.

5. Race condition və konfliktlərdən qorunma

Bəzən bir faylı eyni anda bir neçə proqram aça bilər (məsələn, sizin C# tətbiqi və Notepad++). Bu səhvlərə gətirə bilər. Default olaraq StreamReaderStreamWriter FileShare-ə əsaslanan paylaşım rejimlərindən istifadə edir — yəni ya başqalarına oxumağa icazə verirlər, ya da yox.

Bunu açıq şəkildə idarə etmək olar:

using var stream = new FileStream("data.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
using var reader = new StreamReader(stream, Encoding.UTF8);
// Oxuma...
  • FileShare.Read: başqaları yalnız oxuya bilər.
  • FileShare.None: paylaşım yoxdur — fayl tamamilə "səndir".

Əgər faylı həm oxumaq, həm yazmaq üçün müxtəlif proqramlar lazım olarsa — müvafiq rejimi seçin, amma bunun nəticələrini yaxşı başa düşün.

6. Gözlənilməz istisnalar və onları necə idarə etmək

Bütün qaydalara əməl etsəniz belə, məsələn, diskdə yerin olmaması, sıradan çıxmış flash və ya virus kimi uğursuzluqlar baş verə bilər. Bir neçə "egzotik" istisna və onları necə tutmaq olar:

  • PathTooLongException — fayl yolu çox uzundur (köhnə Windows versiyalarında 260 simvoldan artıq).
  • DirectoryNotFoundException — göstərilmiş qovluq tapılmadı.
  • DriveNotFoundException — məsələn, yol "Z:\\file.txt" kimidirsə və Z diski yoxdur.
  • NotSupportedException — məsələn, yol icazəsiz kombinasiyanı ehtiva edir.

Bu tip istisnalar üçün ayrıca blok etmək və ən azından loglamaq məsləhətdir.

7. Atomik yazma üçün müvəqqəti fayllardan istifadə

Klassik problem: faylı yazırsan, amma proqram ortasında bağlanır — nəticədə fayl korlanır. Peşəkar proqramlar adətən "atomik" yazma strategiyasından istifadə edirlər:

  1. Məzmunu müvəqqəti fayla yazmaq (məsələn, "file.txt.tmp").
  2. Müvəqqəti faylı əsas faylın üstünə köçürmək (bu əməliyyat fayl sistemi səviyyəsində adətən atomikdir) — File.Replace.
  3. Köhnə fayl tamamilə əvəz olunur və ya heç dəyişmir — yarımçıq məlumat olmaz.

Nümunə:

string tempPath = path + ".tmp";
try
{
    using var writer = new StreamWriter(tempPath, false, Encoding.UTF8);
    // Hər şeyi müvəqqəti fayla yazırıq
    writer.Write(contentForSave);
    // Uğurlu yazıdan sonra əsas faylı əvəz edirik
    File.Replace(tempPath, path, null); // Müvəqqəti faylı əsas faylla atomik şəkildə əvəz edir
}
catch (Exception ex)
{
    Console.WriteLine("Faylın saxlanmasında xəta: " + ex.Message);
    // tempPath faylını silmək yaxşıdır, əgər lazım deyilsə
}

Reallıqda bir çox redaktorlar və ofis paketləri məlumatların konsistentliyini təmin etmək üçün bu yanaşmanı istifadə edir.

8. Təhlükəsiz giriş üçün wrapper-klaslardan istifadə

.NET "təhülkəsiz" fayl əməliyyatları üçün köməkçi metodlar təklif edir. Məsələn, File.ReadAllTextFile.WriteAllText avtomatik olaraq faylı açıb oxuyur/yazır və bağlayır. Amma onları da try-catch ilə örtmək lazımdır:

try
{
    string text = File.ReadAllText("settings.json", Encoding.UTF8);
    // Məlumatla işləyirik...
}
catch (Exception ex)
{
    Console.WriteLine("Faylla işləmədə xəta: " + ex.Message);
}

Böyük fayllar üçün isə stream-lərdən istifadə edib faylı hissə-hissə oxuyun, birdən-birə bütün RAM-ı doldurmayasınız.

1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Tipik istisnalar
Fayllarla işləyərkən error-ların idarə olunması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION