CodeGym /Kurslar /C# SELF /Bayt axınları ilə işləmək

Bayt axınları ilə işləmək

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

1. Giriş

Artıq biz axınlar (Stream) ilə tanışıq, bunlar məlumatların ardıcıl oxunması və ya yazılması üçün abstraksiyadır. Biz FileStream ilə fayllara bayt səviyyəsində çıxış əldə etmişik, həmçinin StreamReaderStreamWriter ilə mətn məlumatları ilə rahat işləmək üçün istifadə etmişik, hansılar ki, əslində FileStream-dən istifadə edir və kodlaşdırmaya görə narahat olmurlar.

Bəs əgər bizə faylda sadəcə mətn yox, dəqiq tipli məlumatlar saxlamaq lazımdırsa: tam ədədlər (int), onluq ədədlər (double, float), boolean dəyərlər (bool), tarixlər (DateTime) və ya hətta öz strukturumuzu? Əlbəttə, bunların hamısını string-ə çevirib StreamWriter ilə yaza bilərik, sonra oxuyanda geri parse edə bilərik. Amma bu yanaşmanın ciddi çatışmazlıqları var:

  • Saxlama qeyri-effektivliyi: 12345 ədədi mətn kimi yazılsa, 5 bayt (simvol) tutur. Binar formada int cəmi 4 bayt tutur. Böyük həcmdə məlumat üçün fərq çox böyük olur.
  • Performans: Ədədləri string-ə və əksinə çevirmək prosessor vaxtı üçün əlavə yükdür.
  • Məlumatın dəqiqliyi: Onluq ədədləri mətnə və geri çevirmək dəqiqlik itkisiylə nəticələnə bilər (yuvarlaqlaşdırma səbəbindən).
  • Parse etmənin çətinliyi: Fərqli tipli məlumatları (məsələn, "123,45 TRUE 2024-06-21") mətn sətirindən əl ilə ayırmaq kodu çətinləşdirir və kövrək edir.

Bu problemləri həll etmək üçün xüsusi BinaryReaderBinaryWriter sinifləri var. Bunlar istənilən əsas Stream (adətən FileStream) üzərində işləyən adapterlərdir və C#-ın primitiv data tiplərini binar formatda oxumaq və yazmaq üçün rahat metodlar təqdim edir. Onlar baytları konkret tiplərə və əksinə çevirmə işini öz üzərinə götürür, beləliklə strukturlaşdırılmış binar fayllarla işi xeyli asanlaşdırır.

Əsas ideya: BinaryReaderBinaryWriter — bunlar ayrıca axın deyil. Onlar mövcud Stream-in funksionallığını gücləndirir, C# tipləri ilə işləmək üçün metodlar əlavə edir, xam baytlarla yox.

2. BinaryWriter ilə məlumat yazmaq

BinaryWriter C#-ın hər primitiv tipi üçün overload olunmuş Write() metodlarını təqdim edir. Bu metod çağırılanda, BinaryWriter dəyəri binar təqdimata (bayt ardıcıllığına) çevirir və bu baytları əsas Stream-ə yazır.

Nümunə: Oyun ayarlarını saxlayırıq

Tutaq ki, oyun ayarlarını saxlamaq istəyirik: səs səviyyəsi (onluq ədəd), oyunçunun cari səviyyəsi (tam ədəd), musiqi açıqdırmı (bool dəyəri) və seçilmiş çətinlik səviyyəsi (string).


string filePath = "settings.bin";

// 1. Yazmaq üçün FileStream yaradırıq
using FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
// 2. FileStream üzərində BinaryWriter yaradırıq, string-lər üçün kodlaşdırmanı göstəririk (əgər olacaqsa)
using BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
// 3. Müxtəlif tipli məlumatları yazırıq
writer.Write(0.75f);       // float (4 bayt)
writer.Write(15);          // int (4 bayt)
writer.Write(true);        // bool (1 bayt)
writer.Write("Easy");      // string (uzunluq prefiksi + baytlar)
                
Console.WriteLine($"Ayarlar '{filePath}' faylına yadda saxlanıldı.");

Nümunənin izahı:

  • FileStream FileMode.Create ilə yaradılır, bu ya yeni fayl yaradır, ya da mövcud faylı sıfırlayır.
  • Sonra BinaryWriter yaradırıq, ona fs ötürürük. Vacibdir ki, BinaryWriter default olaraq əsas axını (fs) bağlayır Dispose() çağırılanda (hansı ki, using bloku ilə avtomatik çağırılır).
  • writer.Write() metodları intuitivdir: Write(float), Write(int), Write(bool), Write(string). Onlar özləri bilirlər, hər tip üçün neçə bayt yazmaq lazımdır və necə təqdim etmək lazımdır.
  • String-lər üçün BinaryWriter avtomatik olaraq uzunluq prefiksi əlavə edir string baytlarından əvvəl. Bu BinaryReader-ə dəqiq bilir ki, string-i bərpa etmək üçün neçə bayt oxumaq lazımdır.
  • settings.bin faylını mətn redaktorunda açmağa çalışsan, "qarışıq" görəcəksən, çünki bu — binar fayldır. Məzmununa baxmaq üçün HEX-redaktor lazımdır.

3. BinaryReader ilə məlumat oxumaq

BinaryReader ReadXxx() (məsələn, ReadInt32(), ReadBoolean(), ReadString()) metodlarını təqdim edir, hansılar ki, əsas Stream-dən uyğun sayda bayt oxuyur və onları lazımi C# tipinə çevirir.

Nümunə: Oyun ayarlarını yükləyirik

İndi əvvəl yaratdığımız settings.bin faylından ayarları oxuyaq.


string filePath = "settings.bin";

// 1. Oxumaq üçün FileStream yaradırıq
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
// 2. FileStream üzərində BinaryReader yaradırıq, eyni kodlaşdırmadan istifadə edirik
using BinaryReader reader = new BinaryReader(fs, Encoding.UTF8);

// 3. Məlumatları YAZILDIĞI EYNİ ARDICIQLIQDA oxuyuruq
float volume = reader.ReadSingle();     // float
int level = reader.ReadInt32();         // int
bool isMusicOn = reader.ReadBoolean();  // bool
string difficulty = reader.ReadString(); // string
                
Console.WriteLine($"Ayarlar '{filePath}' faylından yükləndi:");
Console.WriteLine($"- Səs səviyyəsi: {volume:P0}"); // Faiz kimi formatlaşdırırıq (string formatlama istifadə olunur)
Console.WriteLine($"- Oyunçu səviyyəsi: {level}");
Console.WriteLine($"- Musiqi açıqdır: {isMusicOn}");
Console.WriteLine($"- Çətinlik: {difficulty}");

Nümunənin izahı:

  • FileStream FileMode.Open rejimində oxumaq üçün açılır.
  • BinaryReader fs üzərində yaradılır, yazarkən istifadə olunan kodlaşdırmanın eynisi göstərilir.
  • Çox vacibdir: reader.ReadXxx() metodlarının çağırılma ardıcıllığı MÜTLƏQ BinaryWriter ilə yazılan ardıcıllığa uyğun olmalıdır. Əgər string oxumağa çalışsan, amma orada int yazılıbsa, EndOfStreamException (əgər string daha uzundursa) və ya səhv məlumat oxunacaq.
  • ReadXxx() metodları avtomatik olaraq lazım olan qədər bayt oxuyur və onları istənilən tipə çevirir. ReadString() isə BinaryWriter tərəfindən yazılmış uzunluq prefiksindən istifadə edir ki, tam string üçün neçə bayt oxumaq lazımdır.

4. Vacib nüanslar və ən yaxşı təcrübələr

Sərt ardıcıllıq:

Əsas qayda budur. BinaryReaderBinaryWriter tip haqqında heç bir metadata saxlamır; onlar sadəcə hər primitiv tipin neçə bayt tutduğunu bilir. Sən ardıcıllığı təmin etməlisən.

Resursların idarə olunması (using):

.NET-də sistem resursları (məsələn, fayllar və ya şəbəkə bağlantıları) ilə işləyən əksər siniflər kimi, həm BinaryReader, həm də BinaryWriter IDisposable interfeysini reallaşdırır. Ona görə də həmişə onları using blokuna qoy — beləliklə, Dispose() avtomatik çağırılacaq, hətta səhv olsa belə. Bu, səni sızmalardan qoruyacaq və faylı düzgün bağlayacaq.

Yeri gəlmişkən, default olaraq BinaryWriterBinaryReader onlara ötürülən əsas axın üçün də Dispose() çağıracaq (məsələn, FileStream), yəni o da avtomatik bağlanacaq.


using FileStream fs = new FileStream("data.bin", FileMode.OpenOrCreate);
using BinaryWriter writer = new BinaryWriter(fs);
// ... iş

String-lər üçün kodlaşdırma:

String-lərlə düzgün işləmək üçün, BinaryWriter.Write(string) ilə yazılan və BinaryReader.ReadString() ilə oxunan string-lər üçün həmişə eyni kodlaşdırmanı konstruktorlarda göstər (məsələn, Encoding.UTF8). Əks halda, ASCII-dən kənar simvollarla problem ola bilər.

İstisnaların işlənməsi:

Fayl oxuma-yazma əməliyyatları həmişə xarici faktorlarla kəsilə bilər (fayl yoxdur, icazə yoxdur, disk doludur). FileStreamBinaryReader/BinaryWriter ilə kodu həmişə try-catch blokuna qoy ki, etibarlılıq təmin olunsun.

BaseStream və mövqe:

Əsas axına BaseStream property-si ilə çıxış edə bilərsən (məsələn, reader.BaseStream və ya writer.BaseStream). Bu, sənə cari mövqeyi (BaseStream.Position) öyrənmək və ya faylda yerini dəyişmək (BaseStream.Seek()) üçün lazımdır.


// BaseStream.Position istifadəsinə nümunə
using FileStream fs = new FileStream("data.bin", FileMode.OpenOrCreate);
using BinaryWriter writer = new BinaryWriter(fs);

writer.Write(123);
Console.WriteLine($"Axında cari mövqe: {writer.BaseStream.Position}"); // 4 çıxacaq (int ölçüsü)

writer.Write("Hello");
Console.WriteLine($"Axında cari mövqe: {writer.BaseStream.Position}"); // 4 + (1+5) = 10 çıxacaq

⚠️ Write(string) metodu əvvəlcə string-in uzunluğunu 7-bitlik tam ədəd kimi yazır, sonra isə string-in baytlarını. Ona görə də yekun ölçü həmişə 1 + string uzunluğuna bərabər olmur.

1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Giriş-çıxış axınları
Faylların oxunması və yazılması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION