MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Fișiere binare - BinaryWriter și BinaryReader

Pentru lucrul cu fișierele binare sunt destinate două clase: BinaryWriter și BinaryReader. Aceste clase permit citirea și scrierea datelor în format binar.

BinaryWriter

Pentru a crea un obiect BinaryWriter se pot folosi mai mulți constructori. Unul dintre cei mai simpli este:

BinaryWriter(Stream stream)

În constructorul său se transmite un obiect Stream (de obicei, acesta este un obiect FileStream).

Principalele metode ale clasei BinaryWriter:

  • Close(): închide fluxul și eliberează resursele
  • Flush(): curăță bufferul, scriind datele rămase din buffer în fișier
  • Seek(): setează poziția în flux
  • Write(): scrie date în flux. Ca parametru, această metodă poate primi valori de tipuri primitive: - Write(bool) - Write(byte) - Write(char) - Write(decimal) - Write(double) - Write(Half) - Write(short) - Write(int) - Write(long) - Write(sbyte) - Write(float) - Write(string) - Write(ushort) - Write(uint) - Write(ulong)

Sau poate primi array-uri de tipuri byte și char:

- Write(byte[]), - Write(char[]), - Write(ReadOnlySpan<byte>), - Write(ReadOnlySpan<char>)

La scrierea unui array, se poate specifica de la ce element al array-ului trebuie să înceapă scrierea, precum și numărul de elemente care urmează să fie scrise:

  • Write(byte[], int, int)
  • Write(char[], int, int)

Să vedem un exemplu simplu de scriere a unui fișier binar:

string path = "person.dat";

// creăm un obiect BinaryWriter
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.OpenOrCreate)))
{
   // scriem în fișier un șir de caractere
   writer.Write("Tom");
   // scriem în fișier un număr de tip int
   writer.Write(37);
   Console.WriteLine("Fișierul a fost scris");
}

În acest caz, în fișierul person.dat sunt scrise două valori: un șir de caractere "Tom" și un număr 37. Pentru crearea obiectului se folosește apelul new BinaryWriter(File.Open(path, FileMode.OpenOrCreate)).

Similar, putem salva date mai complexe. De exemplu, să salvăm în fișier un array de obiecte:

string path = "people.dat";

// array pentru scriere
Person[] people =
{
   new Person("Tom", 37),
   new Person("Bob", 41)
};

using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.OpenOrCreate)))
{
   // scriem în fișier valoarea fiecărei proprietăți a obiectului
   foreach (Person person in people)
   {
       writer.Write(person.Name);
       writer.Write(person.Age);
   }
   Console.WriteLine("Fișierul a fost scris");
}

class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
   public Person(string name, int age)
   {
       Name = name;
       Age = age;
   }
}

În acest exemplu, salvăm secvențial în fișierul people.dat datele obiectelor Person din array-ul people.

BinaryReader

Pentru a crea un obiect BinaryReader se pot folosi mai mulți constructori. Una dintre cele mai simple versiuni este:

Reader(Stream stream)

Constructorul său primește, de asemenea, un obiect Stream (de obicei, un obiect FileStream).

Principalele metode ale clasei BinaryReader:

  • Close(): închide fluxul și eliberează resursele
  • ReadBoolean(): citește o valoare de tip bool și mută pointerul cu un byte înainte
  • ReadByte(): citește un byte și mută pointerul cu un byte înainte
  • ReadChar(): citește o valoare de tip char, adică un caracter, și mută pointerul cu numărul de bytes ocupat de caracter în codificarea curentă
  • ReadDecimal(): citește o valoare de tip decimal și mută pointerul cu 16 bytes înainte
  • ReadDouble(): citește o valoare de tip double și mută pointerul cu 8 bytes înainte
  • ReadInt16(): citește o valoare de tip short și mută pointerul cu 2 bytes înainte
  • ReadInt32(): citește o valoare de tip int și mută pointerul cu 4 bytes înainte
  • ReadInt64(): citește o valoare de tip long și mută pointerul cu 8 bytes înainte
  • ReadSingle(): citește o valoare de tip float și mută pointerul cu 4 bytes înainte
  • ReadString(): citește un șir de caractere. Fiecare șir este precedat de valoarea lungimii sale, care reprezintă un număr întreg de 7 biți

Citirea datelor binare este simplă: metoda corespunzătoare citește datele unui anumit tip și mută pointerul cu dimensiunea acestui tip în bytes. De exemplu, valoarea de tip int ocupă 4 bytes, deci BinaryReader va citi 4 bytes și va muta pointerul cu acești 4 bytes.

De exemplu, în exemplul anterior cu BinaryWriter am scris în fișierul person.dat un șir de caractere și un număr. Să le citim cu ajutorul BinaryReader:

using (BinaryReader reader = new BinaryReader(File.Open("person.dat", FileMode.Open)))
{
   // citim din fișier un șir de caractere
   string name = reader.ReadString();
   // citim din fișier un număr
   int age = reader.ReadInt32();
   Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

Constructorul clasei BinaryReader primește, de asemenea, un obiect de flux, dar în acest caz stabilim modul de deschidere ca FileMode.Open: new BinaryReader(File.Open("person.dat", FileMode.Open)).

În ordinea în care datele au fost scrise în fișier, în aceeași ordine le putem citi de acolo. Deci, dacă mai întâi a fost scris un șir de caractere, apoi un număr, atunci în această ordine le putem citi din fișier.

Sau, similar, putem citi datele din fișierul people.dat, care a fost scris în exemplul de mai sus și care conține datele obiectelor Person:

// listă pentru datele citite
List<Person> people = new List<Person>();

// creăm un obiect BinaryReader
using (BinaryReader reader = new BinaryReader(File.Open("people.dat", FileMode.Open)))
{
   // până când nu este atins sfârșitul fișierului
   // citim fiecare valoare din fișier
   while (reader.PeekChar() > -1)
   {
       string name = reader.ReadString();
       int age = reader.ReadInt32();
       // pe baza datelor citite creăm un obiect Person și îl adăugăm în listă
       people.Add(new Person(name, age));
   }
}
// afișăm conținutul listei people în consolă
foreach(Person person in people)
{
   Console.WriteLine($"Nume: {person.Name}  Vârstă: {person.Age}");
}

class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
   public Person(string name, int age)
   {
       Name = name;
       Age = age;
   }
}

Aici citim datele într-un ciclu while. Pentru a afla sfârșitul fluxului, apelăm metoda PeekChar(). Această metodă citește următorul caracter și returnează reprezentarea sa numerică. Dacă caracterul nu există, metoda returnează -1, ceea ce va indica faptul că am ajuns la sfârșitul fișierului.

În ciclu, citim secvențial valorile proprietăților obiectelor Person în aceeași ordine în care au fost scrise.

← Lecția anterioară Lecția următoare →