Samouczek programowania C dotyczący obsługi plików o swobodnym dostępie

Oprócz najprostszych aplikacji większość programów musi czytać lub zapisywać pliki. Może to być po prostu odczyt pliku konfiguracyjnego, parsera tekstu lub czegoś bardziej zaawansowanego. Ten samouczek koncentruje się na korzystaniu z plików o swobodnym dostępie w C.

Programowanie we / wy pliku o swobodnym dostępie w C

plik binarny
D3Damon / Getty Images

Podstawowe operacje na plikach to:

  • fopen - otwórz plik - określ sposób jego otwierania (odczyt / zapis) i wpisz (binarny / tekst)
  • fclose - zamknij otwarty plik
  • fread - odczytany z pliku
  • fwrite - zapisz do pliku
  • fseek / fsetpos - przenieś wskaźnik pliku w dowolne miejsce w pliku
  • ftell / fgetpos - informuje, gdzie znajduje się wskaźnik pliku

Dwa podstawowe typy plików to tekst i dwójkowy. Z tych dwóch plików binarnych zwykle łatwiej jest sobie poradzić. Z tego powodu i faktu, że losowy dostęp do pliku tekstowego nie jest czymś, co trzeba często robić, ten samouczek jest ograniczony do plików binarnych. Pierwsze cztery wymienione powyżej operacje dotyczą plików tekstowych i plików o swobodnym dostępie. Dwa ostatnie tylko dla losowego dostępu.

instagram viewer

Losowy dostęp oznacza, że ​​możesz przejść do dowolnej części pliku i czytać lub zapisywać z niego dane bez konieczności czytania całego pliku. Wiele lat temu dane były przechowywane na dużych rolkach taśmy komputerowej. Jedynym sposobem na dotarcie do punktu na taśmie było przeczytanie całej taśmy. Potem pojawiły się dyski i teraz możesz bezpośrednio odczytać dowolną część pliku.

Programowanie z plikami binarnymi

Plik binarny to plik o dowolnej długości, który zawiera bajty o wartościach z zakresu od 0 do 255. Bajty te nie mają innego znaczenia niż w pliku tekstowym, w którym wartość 13 oznacza powrót karetki, 10 oznacza przejście do wiersza, a 26 oznacza koniec pliku. Oprogramowanie odczytujące pliki tekstowe musi radzić sobie z tymi innymi znaczeniami.

Pliki binarne to strumień bajtów, a współczesne języki mają tendencję do pracy ze strumieniami, a nie z plikami. Ważną częścią jest strumień danych, a nie skąd pochodzi. W do, możesz myśleć o danych jako plikach lub strumieniach. Dzięki losowemu dostępowi możesz czytać lub zapisywać w dowolnej części pliku lub strumienia. Przy dostępie sekwencyjnym musisz od początku przeglądać plik lub strumień jak dużą taśmę.

Ten przykładowy kod pokazuje prosty plik binarny otwierany do zapisu, w którym zapisany jest ciąg tekstowy (char *). Zwykle widzisz to w pliku tekstowym, ale możesz pisać tekst do pliku binarnego.

Ten przykład otwiera plik binarny do zapisu, a następnie zapisuje w nim znak char * (ciąg). Zmienna FILE * jest zwracana z wywołania fopen (). Jeśli to się nie powiedzie (plik może istnieć i być otwarty lub tylko do odczytu albo może wystąpić błąd w nazwie pliku), wówczas zwraca 0.

Komenda fopen () próbuje otworzyć określony plik. W tym przypadku jest to plik test.txt w tym samym folderze co aplikacja. Jeśli plik zawiera ścieżkę, należy podwoić wszystkie odwrotne ukośniki. „c: \ folder \ test.txt” jest niepoprawny; musisz użyć „c: \\ folder \\ test.txt”.

Ponieważ tryb pliku to „wb”, ten kod zapisuje do pliku binarnego. Plik jest tworzony, jeśli nie istnieje, a jeśli tak, to cokolwiek w nim jest, jest usuwane. Jeśli wywołanie fopen nie powiedzie się, być może dlatego, że plik był otwarty lub nazwa zawiera nieprawidłowe znaki lub nieprawidłową ścieżkę, fopen zwraca wartość 0.

Chociaż możesz po prostu sprawdzić, czy ft jest niezerowy (sukces), w tym przykładzie jest funkcja FileSuccess (), aby to zrobić jawnie. W systemie Windows generuje powodzenie / niepowodzenie połączenia i nazwę pliku. Jest to trochę uciążliwe, jeśli zależy Ci na wydajności, więc możesz ograniczyć to do debugowania. W systemie Windows nakładanie tekstu na debuger systemowy jest niewielkie.

Wywołania fwrite () generują określony tekst. Drugi i trzeci parametr to rozmiar znaków i długość łańcucha. Oba są zdefiniowane jako size_t, który jest liczbą całkowitą bez znaku. Wynikiem tego połączenia jest zapisanie elementów liczących o określonym rozmiarze. Zauważ, że w przypadku plików binarnych, nawet jeśli piszesz ciąg znaków (char *), nie dołącza on żadnych znaków powrotu karetki ani znaku końca wiersza. Jeśli chcesz, musisz je jawnie dołączyć do ciągu.

Tryby plików do odczytu i zapisu plików

Kiedy otwierasz plik, określasz, jak ma być otwierany - czy chcesz go utworzyć z nowego, czy nadpisać, czy tekst, czy plik binarny, odczyt lub zapis oraz czy chcesz do niego dołączyć. Odbywa się to za pomocą jednego lub więcej specyfikatorów trybu pliku, które są pojedynczymi literami „r”, „b”, „w”, „a” i „+” w połączeniu z innymi literami.

  • r - Otwiera plik do odczytu. Nie powiedzie się, jeśli plik nie istnieje lub nie można go znaleźć.
  • w - Otwiera plik jako pusty plik do zapisu. Jeśli plik istnieje, jego zawartość zostanie zniszczona.
  • a - Otwiera plik do zapisu na końcu pliku (dołączanie) bez usuwania znacznika EOF przed zapisaniem nowych danych do pliku; najpierw tworzy plik, jeśli nie istnieje.

Dodanie „+” do trybu pliku tworzy trzy nowe tryby:

  • r + - Otwiera plik do odczytu i zapisu. (Plik musi istnieć.)
  • w + - Otwiera plik jako pusty plik do odczytu i zapisu. Jeśli plik istnieje, jego zawartość zostanie zniszczona.
  • a + - Otwiera plik do odczytu i dołączenia; operacja dołączania obejmuje usunięcie znacznika EOF przed zapisaniem nowych danych do pliku, a znacznik EOF jest przywracany po zakończeniu zapisu. Najpierw tworzy plik, jeśli nie istnieje. Otwiera plik do odczytu i dołączenia; operacja dołączania obejmuje usunięcie znacznika EOF przed zapisaniem nowych danych do pliku, a znacznik EOF jest przywracany po zakończeniu zapisu. Najpierw tworzy plik, jeśli nie istnieje.

Kombinacje trybu pliku

Ta tabela pokazuje kombinacje trybów plików dla plików tekstowych i binarnych. Zasadniczo albo odczytujesz, albo zapisujesz do pliku tekstowego, ale nie jedno i drugie jednocześnie. Za pomocą pliku binarnego można zarówno czytać, jak i zapisywać w tym samym pliku. Poniższa tabela pokazuje, co możesz zrobić z każdą kombinacją.

  • r tekst - czytaj
  • rb + binarny - czytaj
  • r + tekst - czytaj, pisz
  • r + b binarny - odczyt, zapis
  • rb + binarny - odczyt, zapis
  • w tekst - pisz, twórz, obcinaj
  • wb binary - pisz, twórz, obcinaj
  • w + tekst - czytaj, pisz, twórz, obcinaj
  • w + binary - odczyt, zapis, tworzenie, obcinanie
  • wb + binary - czytaj, pisz, twórz, obcinaj
  • tekst - pisz, twórz
  • ab binary - pisz, twórz
  • + tekst - czytaj, pisz, twórz
  • a + binarny - pisz, twórz
  • ab + binary - pisz, twórz

Jeśli nie tworzysz tylko pliku (użyj „wb”) lub tylko go czytasz (użyj „rb”), możesz uciec od używania „w + b”.

Niektóre implementacje dopuszczają także inne litery. Microsoftpozwala na przykład:

  • t - tryb tekstowy
  • c - zatwierdzenie
  • n - brak zatwierdzenia
  • S - optymalizacja buforowania dla dostępu sekwencyjnego
  • R - buforowanie niesekwencyjne (dostęp losowy)
  • T - tymczasowy
  • D - usuń / tymczasowy, który zabija plik, gdy jest zamknięty.

Nie są przenośne, więc używaj ich na własne ryzyko.

Przykład przechowywania plików o losowym dostępie

Głównym powodem korzystania z plików binarnych jest elastyczność, która pozwala na odczyt lub zapis w dowolnym miejscu pliku. Pliki tekstowe umożliwiają tylko czytanie lub pisanie sekwencyjne. Z przewagą niedrogich lub bezpłatnych baz danych, takich jak SQLite i MySQL, zmniejsza potrzebę korzystania z losowego dostępu do plików binarnych. Jednak losowy dostęp do rekordów plików jest trochę staromodny, ale nadal przydatny.

Badanie przykładu

Załóżmy, że w przykładzie pokazano parę indeksów i plików danych przechowujących ciągi w pliku o swobodnym dostępie. Ciągi mają różne długości i są indeksowane według pozycji 0, 1 i tak dalej.

Istnieją dwie nieważne funkcje: CreateFiles () i ShowRecord (int recnum). CreateFiles używa bufora char * o rozmiarze 1100 do przechowywania łańcucha tymczasowego złożonego z ciągu formatu msg, po którym następuje n gwiazdek, gdzie n zmienia się od 5 do 1004. Two FILE * są tworzone za pomocą obu trybów plików wb w zmiennych ftindex i ftdata. Po utworzeniu służą do manipulowania plikami. Te dwa pliki są

  • index.dat
  • data.dat

Plik indeksu zawiera 1000 rekordów typu typ indeksu; jest to typ struktury struct, który ma dwa elementy pos (typu fpos_t) i rozmiar. Pierwsza część pętli:

wypełnia ciąg msg w ten sposób.

i tak dalej. Wtedy to:

wypełnia strukturę długością łańcucha i punktem w pliku danych, w którym łańcuch zostanie zapisany.

W tym momencie zarówno struktura pliku indeksu, jak i ciąg pliku danych mogą być zapisywane w odpowiednich plikach. Chociaż są to pliki binarne, są zapisywane sekwencyjnie. Teoretycznie możesz zapisywać rekordy do pozycji poza bieżącym końcem pliku, ale nie jest to dobra technika do użycia i prawdopodobnie wcale nie jest przenośna.

Ostatnią częścią jest zamknięcie obu plików. Dzięki temu ostatnia część pliku zostanie zapisana na dysku. Podczas zapisywania plików wiele zapisów nie przechodzi bezpośrednio na dysk, ale jest przechowywanych w buforach o stałej wielkości. Po zapełnieniu zapisu przez bufor cała zawartość bufora jest zapisywana na dysku.

Funkcja opróżniania plików wymusza opróżnianie, można także określić strategie opróżniania plików, ale są one przeznaczone dla plików tekstowych.

Funkcja ShowRecord

Aby przetestować, czy można pobrać dowolny określony rekord z pliku danych, musisz wiedzieć dwie rzeczy: gdzie zaczyna się w pliku danych i jak duży jest.

Tak właśnie działa plik indeksu. Funkcja ShowRecord otwiera oba pliki, szuka odpowiedniego punktu (recnum * sizeof (typ indeksu) i pobiera liczbę bajtów = sizeof (indeks).

SEEK_SET jest stałą, która określa, z którego miejsca wykonywany jest fseek. W tym celu zdefiniowano dwie inne stałe.

  • SEEK_CUR - szukaj względem bieżącej pozycji
  • SEEK_END - wyszukaj absolut z końca pliku
  • SEEK_SET - szukaj wartości absolutnej od początku pliku

Możesz użyć SEEK_CUR, aby przesunąć wskaźnik pliku do przodu o rozmiarof (indeks).

Po uzyskaniu rozmiaru i pozycji danych pozostaje tylko pobrać.

Tutaj użyj fsetpos () ze względu na typ index.pos, którym jest fpos_t. Alternatywnym sposobem jest użycie ftell zamiast fgetpos i fsek zamiast fgetpos. Pary fseek i ftell działają z int, podczas gdy fgetpos i fsetpos używają fpos_t.

Po wczytaniu rekordu do pamięci dodawany jest znak zerowy \ 0, aby przekształcić go we właściwy Ciąg c. Nie zapomnij, bo dojdzie do awarii. Tak jak poprzednio, fclose jest wywoływany dla obu plików. Chociaż nie stracisz żadnych danych, jeśli zapomnisz fclose (w przeciwieństwie do zapisów), będziesz mieć przeciek pamięci.

instagram story viewer