CodeGym /Kurslar /C# SELF /Giriş-çıxış axınları: Stre...

Giriş-çıxış axınları: Stream

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

1. Giriş

Gəlin təsəvvür edək ki, bir çaydan su var. Krana açırsan — su axmağa başlayır. Çoxlu su yığıb birdən tökmək olar, ya da çaydanı az-az doldurmaq olar. Fayllarla da eyni vəziyyətdir — heç də həmişə bütün faylı bir anda yaddaşa yükləmək rahat və ya mümkün olmur. Fayllar böyük ola bilər, bəzən isə məlumat mənbəyi fayl yox, məsələn, şəbəkə bağlantısı olur və məlumatlar tədricən gəlir.

Əgər biz həmişə sadəcə byte massivi ilə işləməyə çalışsaydıq, böyük fayllarda yaddaşımız tez bitərdi, həm də "sonsuz" məlumat axınları üçün (məsələn, video və ya audio axınları) bu yanaşma işləməzdi. Bax, burada axın konsepsiyası köməyə gəlir!

.NET-də axın — məlumatlara ardıcıl çıxış üçün abstraksiyadır: mənbənin nə olduğu fərq etmir — fayl, şəbəkə, yaddaş, ya da hətta sıxılmış arxiv kimi ekzotik bir şey. Axın sənə məlumatları hissə-hissə oxumağa və yazmağa imkan verir, adətən bloklarla və ya baytlarla.

Əsas ideya:

  • Axın — məlumat ötürmək üçün kanaldır. O, konveyer kimidir: sən "qoya" (yaza) və ya "götürə" (oxuya) bilərsən, harada və necə saxlanıldığını birbaşa düşünmədən.
  • Məlumatlar ardıcıl gəlir: növbəti hissəni yalnız əvvəlkini oxuduqdan sonra oxuya bilərsən (ya da əksinə, əgər geri çəkmə dəstəklənirsə).
  • Çox vaxt bütün məlumatı bir anda yaddaşda saxlamırsan (və kompüter buna görə sənə təşəkkür edəcək).

Bu abstraksiya .NET-də demək olar ki, bütün giriş-çıxış əməliyyatlarının əsasındadır: fayllarla, şəbəkələrlə, arxivlərlə, hətta konsolla işləmək!

2. Axınlar System.IO.Stream

İrsi və arxitektura: System.IO.Stream

.NET-də demək olar ki, bütün axınlar abstrakt System.IO.Stream sinifindən miras alır. O, axını oxumaq, yazmaq, axında hərəkət etmək və onu idarə etmək üçün əsas metodları müəyyən edir.


classDiagram
    class Stream {
        +Read()
        +Write()
        +Seek()
        +CanRead
        +CanWrite
        +CanSeek
        +Length
        +Position
    }
    class FileStream
    class MemoryStream
    class NetworkStream
    class CryptoStream
    Stream <|-- FileStream
    Stream <|-- MemoryStream
    Stream <|-- NetworkStream
    Stream <|-- CryptoStream
.NET-də axınların irsi sxemi
  • Stream — əsas abstrakt sinif
  • FileStream — fayllarla işləmək üçün
  • MemoryStream — yaddaşdakı məlumatlarla işləmək üçün
  • NetworkStream — şəbəkə ilə işləmək üçün
  • CryptoStream — şifrələmə/deşifrələmə üçün

Axının əsas property və metodları ilə qısa tanışlıq

Property / Metod Təsviri
CanRead
Bu axından oxumaq mümkündürmü
CanWrite
Bu axına yazmaq mümkündürmü
CanSeek
Axında hərəkət etmək mümkündürmü (hamısı dəstəkləmir)
Length
Axının uzunluğu (əgər dəstəklənirsə — bütün axınlarda olmur)
Position
Axında cari mövqe
Read(...)
Məlumat oxumaq
Write(...)
Məlumat yazmaq
Seek(...)
Axında hərəkət etmək
Flush()
Buffer-i sıfırlamaq (bütün yığılanı axına yazmaq)
Close()
/
Dispose()
Axını bağlamaq və resursları azad etmək

Gəlin baxaq, bu "praktikada" necə görünür.

3. Nümunə: Faylları Stream ilə oxumaq və yazmaq

Axını "işdə" görmək üçün kifayət qədər minimal bir nümunə:


// Yazmaq üçün faylı açırıq
using var stream = new FileStream("numbers.bin", FileMode.Create);

// Təsəvvür et ki, 1-dən 10-a qədər ədədləri fayla yazmaq istəyirik
for (int i = 1; i <= 10; i++)
{
    byte val = (byte)i;
    stream.WriteByte(val); // Hər dəfə bir bayt yazırıq
}

// Faylı açıq şəkildə bağlayırıq ki, onu oxumaq üçün açaq
stream.Close(); 

// İndi bu ədədləri geri oxumağa çalışaq
using var stream2 = new FileStream("numbers.bin", FileMode.Open);
int value;
while ((value = stream2.ReadByte()) != -1)
{
    Console.WriteLine(value); // 1, 2, ... 10 çıxacaq
}

Burada biz FileStream istifadə edirik, hansı ki, axının tam mənasında axındır: sən məlumatı bloklarla və ya baytlarla oxuyur və yazırsan.

Axın növləri: harada rast gələ bilərsən?

Axın — mütləq diskdəki fayl deyil. Budur, axın konsepsiyasının istifadə olunduğu bir neçə nümunə:

  • Diskdə fayl (məsələn, FileStream — ən çox rast gəlinən hal)
  • Operativ yaddaşda axın (MemoryStream — müvəqqəti və ya aralıq məlumatlar üçün rahatdır)
  • Şəbəkə bağlantısı (NetworkStream)
  • Sıxılma/arxivləşdirmə (GZipStream, DeflateStream)
  • Şifrələmə (CryptoStream)
  • Konsol giriş/çıxış (bəli-bəli!) — texniki olaraq, bunlar da axındır

Bu, kodunu yazmağa imkan verir ki, konkret mənbə/qəbuledici barədə düşünməyəsən: əgər kodun axınla işləyirsə, deməli o, universaldır!

4. Faydalı nüanslar

Oxumaq və yazmaq — məlumatı hissə-hissə ötürmək əməliyyatlarıdır. Adətən byte massivi və Read, Write metodları ilə.

Nümunə: faylı bloklarla oxumaq

byte[] buffer = new byte[1024]; // 1024 baytlıq buffer (1 KB)
using var stream = new FileStream("bigfile.bin", FileMode.Open);

int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
    // buffer daxilində yalnız bytesRead baytı emal edirik
    int sum = 0;
    for (int i = 0; i < bytesRead; i++)
        sum += buffer[i];

    Console.WriteLine($"Blokun cəmi: {sum}");
}

Bu yanaşma hər yerdə istifadə olunur — antiviruslardan tutmuş musiqi pleyerlərinə qədər.

Axında mövqe dəyişmək (Position, Seek)

Axınların çoxunda (məsələn, fayl axınlarında) məlumatlar üzrə hərəkət etmək olar — sadəcə "növbəti hissə"ni oxumaq yox, konkret mövqeyə keçib oradan işləmək.

using var stream = new FileStream("numbers.bin", FileMode.Open);
stream.Position = 5; // 6-cı bayta keçir (sıfırdan sayılır)
int value = stream.ReadByte();
Console.WriteLine($"Fayldakı 6-cı bayt: {value}");

Axınlar yalnız oxumaq, yalnız yazmaq və ya hər ikisi üçün ola bilər

Bəzi axınlar yalnız bir variantı dəstəkləyir:

  • Yazmaq üçün açılmış fayl: yalnız Write()
  • Şəbəkə məlumatı oxumaq üçün axın: yalnız Read()
  • Bəzi ekzotik hallarda (məsələn, printerə çıxış axını) ümumiyyətlə "geri çəkmək" və ya axında mövqe dəyişmək mümkün deyil (geri getmək olmur).

Dəstəklənən əməliyyatları CanRead, CanWrite, CanSeek property-ləri ilə yoxla:

using var stream = new FileStream("myfile.txt", FileMode.OpenOrCreate);
if (stream.CanRead)
    Console.WriteLine("Oxumaq dəstəklənir");
if (stream.CanWrite)
    Console.WriteLine("Yazmaq dəstəklənir");
if (stream.CanSeek)
    Console.WriteLine("Faylda hərəkət etmək olar");

Axınlarda bufferləşmə

Demək olar ki, bütün axınlar performansı artırmaq üçün daxili bufferlərdən istifadə edir. Bufferləşmə diskə/şəbəkəyə müraciətləri azaldır: məlumatlar daxildə toplanır, sonra toplu şəkildə verilir/yazılır.

Flush() metodu buffer-i sıfırlamağa imkan verir (məsələn, hər şeyin diskə yazıldığına əmin olmaq üçün):

using var stream = new FileStream("log.txt", FileMode.Append);
byte[] bytes = Encoding.UTF8.GetBytes("Salam, Stream!\n");
stream.Write(bytes, 0, bytes.Length);
stream.Flush(); // Yazının mütləq diskə getdiyinə zəmanət verir

Əgər həyati vacib məlumat yazırsansa (məsələn, ödəniş əməliyyatları!), Flush() çağırmaq — sənin dostundur.

5. Axınlarla işləyərkən tipik səhvlər

Çox vaxt yeni başlayanlar belə səhvlər edirlər:

Axını bağlamağı unudurlar (və yaddaş sızmaları, "asılı" fayllar və başqa əyləncələr alırlar).

Mətn və binar axınları qarışdırırlar — sətiri bayt metodu ilə yazmağa çalışırlar, sonra "qaraqara"lar alırlar.

Çox kiçik buffer istifadə edirlər (ya da ümumiyyətlə buffersiz) — əməliyyatlar ləng olur.

Düşünürlər ki, Read() həmişə istədiyin qədər bayt oxuyur — əslində, daha az qaytara bilər; həmişə qaytarılan dəyəri yoxlamaq lazımdır.

Bütün axınların mövqe dəyişməni (Seek) dəstəkləmədiyini nəzərə almırlar, xüsusilə şəbəkə axınlarında.

Məsələn:


// Pis nümunə: fayldan bütün baytları oxuyarkən həqiqətən neçə bayt oxunduğunu yoxlamırıq
byte[] buffer = new byte[1024];
using (var stream = new FileStream("data.bin", FileMode.Open))
{
    int bytesRead = stream.Read(buffer, 0, 1024);
    // bytesRead fayl kiçikdirsə, 1024-dən az ola bilər!
}
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION