CodeGym /Kursy /C# SELF /Formaty plików: Tekstowe i Binarnie

Formaty plików: Tekstowe i Binarnie

C# SELF
Poziom 35 , Lekcja 1
Dostępny

1. Pliki tekstowe

Pamiętaj: komputer wszystko, absolutnie wszystko, przechowuje jako jedynki i zera (albo, jeśli nie boisz się trudnych słów — jako sekwencję bajtów). Ale jeśli dasz dwóm programom ten sam plik, nie ma gwarancji, że oba zareagują na niego tak samo. Powiedzmy, jeden program zobaczy w nim zwykły tekst, a drugi — zestaw "uszkodzonych bajtów". Wszystko zależy od formatu pliku — czyli jak dokładnie te bajty są interpretowane. Format opisuje wewnętrzną strukturę danych, zasady ich odczytu i kodowanie. Bez znajomości formatu program może po prostu nie zrozumieć, co jest zapisane w pliku.

Plik tekstowy — to plik, w którym dane są przedstawione jako zwykły tekst w jakimś kodowaniu (najczęściej — UTF-8 albo, jeśli chcesz oldschoolowo — ASCII). Zawartość takiego pliku możesz otworzyć w dowolnym edytorze tekstu (np. w Notepadzie albo VS Code) i od razu przeczytać — to są linie znaków, a nie tajemnicze bajty sterujące czy binarne struktury.

Typowe przykłady

  • *.txt — zwykłe pliki tekstowe, np. "to-do.txt" albo "best-books.txt".
  • *.csv — pliki, gdzie dane są rozdzielone przecinkami lub średnikami (wygodne do tabel).
  • *.json — pliki do wymiany danych strukturalnych (np. listy książek).
  • *.xml,*.html — do przechowywania i przesyłania danych strukturalnych.

Przykład pliku CSV


Diuna;Frank Herbert;1965
1984;George Orwell;1949
Mistrz i Małgorzata;Michaił Bułhakow;1966
Przykład zawartości books.txt (format CSV)

Każda linia — to osobny rekord (np. książka). Wartości w linii są rozdzielone średnikiem, co czyni plik przykładem CSV (Comma-Separated Values). Comma — to niby przecinek, ale tutaj przecinek został zastąpiony innym separatorem (;). Znaki, które widzi człowiek, to te same bajty, które czyta program, pod warunkiem, że wie jak zinterpretować tekstowy format i kodowanie pliku.

Jak program pracuje z plikiem tekstowym

Wystarczy otworzyć plik "jako tekst" i można czytać linia po linii. Przykład (przyda się na kolejnych wykładach):


// Proste czytanie linii z pliku (szczegóły omówimy wkrótce)
string[] lines = File.ReadAllLines("books.txt");
foreach (string line in lines)
{
    Console.WriteLine(line);
}

Zalety plików tekstowych

  • Czytelne dla człowieka (human-readable).
  • Łatwo edytować ręcznie (nawet w najprostszym Notepadzie).
  • Świetne do debugowania i wymiany między różnymi systemami.
  • Łatwo przenosić między różnymi platformami (Windows, Linux, Mac).

Wady plików tekstowych

  • Brak ścisłej struktury (txt), łatwo przypadkowo wprowadzić błąd formatu.
  • Zajmują więcej miejsca (np. liczba 12345 = 5 bajtów, a binarnie — 4).
  • Trudno lub niemożliwe przekazywanie skomplikowanych danych (np. obrazki, audio) przez tekst.
  • Wydajność: wolniejsze przy dużych ilościach danych.

Warto wiedzieć

  • Różne platformy różnie rozumieją "koniec linii": Windows — \r\n, Unix — \n.
  • Kodowania mogą się różnić (UTF-8, UTF-16, ANSI itd.), więc plik zapisany w jednym systemie może wyświetlać się jako "chińskie znaczki" w innym (to po prostu błędna interpretacja bajtów).

2. Pliki binarne

Plik binarny — to plik, w którym przechowywane są nie znaki, a dowolne bajty. Mogą oznaczać cokolwiek: liczby, struktury, obrazki, muzykę, nawet kod maszynowy. Spróbuj otworzyć .exe w Notatniku — zobaczysz masę niezrozumiałych znaków!

Typowe przykłady

  • *.exe, *.dll — pliki wykonywalne i biblioteki.
  • *.jpg, *.png, *.gif— obrazki.
  • *.mp3, *.wav— pliki audio.
  • *.dat — pliki z dowolnymi danymi użytkownika.
  • Specyficzne dla aplikacji formaty (*.docx, *.xlsx itd.) — prawie zawsze binarne.

Jak zbudowany jest plik binarny?

Bajt po bajcie, program zapisuje i czyta dane w potrzebnym mu formacie. Na przykład liczba typu int zapisze się na 4 bajtach (32 bity), a string — to zwykle długość + same bajty znaków w określonym kodowaniu.

W pliku tekstowym liczba 12345 — to bajty odpowiadające znakom '1', '2', '3', '4', '5':

Znak Kod UTF-8
1 49
2 50
3 51
4 52
5 53

W pliku binarnym int 12345 (mały porządek bajtów, little-endian) będzie tak:

Pozycja Bajt (hex) Wartość
0 0x39 57
1 0x30 48
2 0x00 0
3 0x00 0

(Innymi słowy: 12345 = 0x00003039.)

Spróbuj zapisać tę samą liczbę w pliku tekstowym i binarnym — i porównaj rozmiar plików. Binarna wersja będzie trochę mniejsza.

Jak program pracuje z plikiem binarnym

Specjalne strumienie (np. BinaryReader, BinaryWriter). W przeciwieństwie do pliku tekstowego, musisz dokładnie znać strukturę, inaczej nie odczytasz danych.


// Przykład zapisu liczb do pliku binarnego
var writer = new BinaryWriter(File.Open("books.bin", FileMode.Create));

// Załóżmy, że zapisujemy kodowanie: ilość znaków (int), potem bajty
string title = "Diuna";
writer.Write(title.Length); // Zapisaliśmy długość (int)
writer.Write(title); // Zapisaliśmy string (będzie w UTF-8)
writer.Write(1965); // Zapisaliśmy rok (int)

writer.Close(); // zamykamy strumień

To tylko przykład. Więcej o pracy z plikami binarnymi opowiem na kolejnych wykładach.

Zalety plików binarnych

  • Kompaktowość: zajmują mniej miejsca.
  • Szybciej się czytają i zapisują (szczególnie przy dużych ilościach danych).
  • Można przechowywać złożone struktury: tablice, zagnieżdżone obiekty itd.

Wady plików binarnych

  • Nieczytelne dla człowieka (human-unreadable).
  • Jeśli struktura pliku się zmieni, stare dane mogą być utracone lub "zepsute".
  • Zawsze potrzebne są dokładne instrukcje do rozbioru zawartości.

3. Jaki format wybrać?

Pliki tekstowe vs binarne

Kryterium Plik tekstowy Plik binarny
Czytelny dla człowieka Tak Nie
Rozmiar Większy Mniejszy
Uniwersalność Wysoka (każdy edytor) Tylko specjalne programy
Szybkość Wolniej Szybciej
Ścisłość formatu Nie Tak, obowiązkowo
Przechowywanie struktur Trudno Łatwo
Ryzyko uszkodzenia danych Niskie (łatwo edytować) Wysokie (najmniejszy błąd — plik nieczytelny)

Kryteria wyboru

  • Potrzebujesz, żeby dane były czytelne dla człowieka, łatwe do zmiany i debugowania? — Użyj pliku tekstowego (np. .txt, .csv, .json).
  • Dane są złożone, ważny jest rozmiar i szybkość? — Format binarny.
  • Trzeba wymieniać dane między różnymi platformami? — Tekstowy jest lepszy, ale kodowanie musi być standardowe (UTF-8).
  • Aplikacja będzie czytać i zapisywać dużo danych, a format jest ścisły? — Wybierz binarny.

W naszej konsolowej aplikacji „Lista książek” na początek idealnie sprawdzi się format tekstowy (.csv lub .txt). Później, gdy struktura się skomplikuje albo będziemy chcieli przyspieszyć ładowanie, można poznać pliki binarne lub przejść na format JSON/XML.

4. Przydatne niuanse

Gdzie w życiu spotykamy pliki tekstowe i binarne?

Pliki tekstowe:

  • Ustawienia programów (często w .ini lub .json).
  • Skrypty, logi, notatki.
  • Pliki importu/eksportu (dane do wymiany między aplikacjami).

Pliki binarne:

  • Programy, gry, biblioteki (tam nikt nie zagląda przypadkiem).
  • Duże bazy danych i archiwa (np. .mdb, .zip).
  • Media: muzyka, zdjęcia, wideo.

Czytanie całego pliku naraz (tekstowa reprezentacja):


string allText = File.ReadAllText("books.txt");
// Teraz allText — wielki string z całą zawartością

Po liniach (optymalnie dla list):


string[] lines = File.ReadAllLines("books.txt");
foreach (string line in lines)
{
    // Można rozbić linię na części
    string[] parts = line.Split(';');
    // parts[0] — tytuł, parts[1] — autor, parts[2] — rok
}

Binarne czytanie — ściśle według struktury


var reader = new BinaryReader(File.Open("books.bin", FileMode.Open));

int count = reader.ReadInt32(); // Ile książek
for (int i = 0; i < count; i++)
{
    string title = reader.ReadString();
    string author = reader.ReadString();
    int year = reader.ReadInt32();
    // Teraz można odtworzyć rekord!
}

reader.Close();

5. Praktyczny przykład: tworzymy plik z książkami

Zapisujemy dane do pliku tekstowego

Będziemy przechowywać każdą książkę w linii formatu:
tytuł;autor;rok pierwszego wydania


// Lista książek, którą chcemy zapisać
var books = new List<(string Title, string Author, int Year)>
{
    ("Diuna", "Frank Herbert", 1965),
    ("1984", "George Orwell", 1949),
    ("Mistrz i Małgorzata", "Michaił Bułhakow", 1966)
};

// Zapisujemy do pliku tekstowego
var writer = new StreamWriter("books.txt");
foreach (var book in books)
    writer.WriteLine($"{book.Title};{book.Author};{book.Year}");

writer.Close();

Możesz otworzyć books.txt w Notatniku i zobaczyć wszystkie dane.

Przechowujemy dane w pliku binarnym

A teraz spróbujmy to samo, ale bardziej kompaktowo (choć nieczytelnie dla człowieka):


var writer = new BinaryWriter(File.Open("books.bin", FileMode.Create));

writer.Write(books.Count); // Zapiszemy ilość książek
foreach (var book in books)
{
    writer.Write(book.Title); // String - będzie: długość + bajty
    writer.Write(book.Author); // String
    writer.Write(book.Year); // Rok (int)
}

writer.Close();

Jeśli spróbujesz otworzyć books.bin w edytorze tekstu, zobaczysz chaos: zestaw nieczytelnych znaków. To normalne. Pliki binarne nie są przeznaczone do czytania przez człowieka — może je poprawnie przetworzyć tylko program, który dokładnie wie, jak ten plik został zapisany.

6. Typowe błędy przy pracy z formatami

Jeśli spróbujesz odczytać plik binarny jako tekstowy, dostaniesz "mieszankę" znaków albo nawet błąd. Podobnie, jeśli otworzysz plik tekstowy jako binarny i oczekujesz ścisłej struktury — będą problemy.

Najczęstszy błąd: niezgodność struktury danych i kolejności odczytu/zapisu. Na przykład najpierw zapiszesz rok, potem tytuł, a czytasz odwrotnie — dostaniesz złe dane. Zawsze zachowuj tę samą kolejność operacji!

Bardzo często programiści "podglądają" plik tekstowy, sprawdzając logikę zapisu i ładowania — właśnie do tego tekstowe formaty są wygodne na początku. Binarne nadają się do zaawansowanych scenariuszy, albo gdy chcesz ukryć szczegóły przechowywania przed użytkownikiem.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION