Informacje o nowych artykułach oraz akcjach edukacyjnych prosto na Twojej skrzynce e-mail!

Obsługa plików w C++ – odczyt danych

Pisząc programy komputerowe na pewno, każdy kiedyś zetknął się z obsługą plików. To właśnie między innymi dzięki plikom, możemy zapisywać ważne informacje wykorzystywane w naszym programie co podniesie jego użyteczność. Po co zresztą komuś aplikacja, która nie potrafi zapamiętać wcześniej wprowadzonych informacji?

Obsługa plików w C++ nie jest tak bardzo skomplikowana jak mogło by się wydawać początkującym programistom, w niniejszym artykule zaprezentuję na praktycznych przykładach sposoby odczytu danych z plików tekstowych oraz binarnych.

Pliki możemy odczytywać za pomocą bibliotek fstreamstdio.h, które zanim zaczniemy cokolwiek robić musimy najpierw zaimportować do naszego programu:

#include <fstream> //import biblioteki fstream
#include <stdio.h> //import biblioteki stdio.h

Kiedy już dołączyliśmy którąś z bibliotek na przykład fstream to możemy się zabrać do dalszej pracy.

getline()

Napiszmy sobie program, który pobiera dane z pliku tekstowego linijka po linijce za pomocą funkcji getline(); i wypisuje je na ekranie. Funkcja getline(uchwytDoPliku, dane); pobiera jedną linijkę z pliku tekstowego.

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    fstream uchwyt; //obiekt typu fstream (uchwyt do pliku)

    uchwyt.open("plik.txt"); //otwieramy plik: plik.txt (plik - nazwa pliku, txt - rozszerzenie)
    string linia;

    do
    {
        getline(uchwyt, linia); //pobierz linijkę
        cout << linia << endl; //wypisz na ekranie
    }
    while(linia != ""); //przerwij jeżeli linia będzie pusta (dane w pliku się skończą) UWAGA: Pamiętaj, żeby w pliku zostawić ostatnią linijkę pustą

    uchwyt.close(); //zamykamy plik

    return 0;
}

Powyższy program wyświetli nam na ekranie zawartość danego pliku tekstowego pobierając wszystkie dane linijka po linijce.

Otwieranie pliku za pomocą funkcji fopen()

Korzystając z biblioteki stdio.h będziemy korzystali z funkcji fopen() do otwarcia pliku. Zobaczmy jak się nią posługiwać:

Ogólna składnia funkcji fopen():

fopen("scierzkaDoPliku.txt", "parmetr");

Za scierzkaDoPliku.txt wstawiamy ścieżkę do pliku który chcemy otworzyć względem naszego pliku z kodem, a w miejscu parametru określamy tryb dostępu do pliku:

Tryb dostępu do plikuOpis
aOtwiera plik tylko do zapisu (jeśli plik nie został stworzony, to zostanie utworzony, wszystkie nowe dane będą zapisywane na jego końcu)
a+Otwiera plik do odczytu i zapisu (jeśli plik nie został stworzony, to zostanie utworzony, wszystkie nowe dane będą zapisywane na jego końcu, można odczytywać dowolny fragment pliku)
bOtwiera plik w trybie binarnym
rOtwiera plik tylko do odczytu (wcześniej musi on zostać stworzony)
r+Otwiera plik do odczytu i zapisu (wcześniej musi on zostać stworzony, można odczytywać i zapisywać dowolny fragment pliku)
wTworzy nowy plik i otwiera tylko do zapisu (uchwyt ustawiany jest na samym początku, a w przypadku kiedy dany plik już istniał to kasowana jest jego zawartość)
w+Tworzony nowy plik i otwiera go do odczytu i zapisu (uchwyt ustawiany jest na samym początku, a w przypadku kiedy dany plik już istniał to kasowana jest jego zawartość, można odczytywać i zapisywać dowolny fragment pliku)

Przykład:

FILE* plik; //uchwyt do pliku

plik = fopen("plik.txt", "r"); //otwieramy plik w trybie tylko do odczytu - parametr "r"

fgetc()

Oczywiście możemy na przykład chcieć pobierać tekst z danego pliku znak po znaku. Problem ten można rozwiązać na przykład wykorzystując bibliotekę stdio.h i funkcję fgetc();. Osobiście wolę właśnie używać tej biblioteki do obsługi plików w C++ gdyż metoda ta jest znacznie szybsza oraz mam większą kontrolę nad pobieranymi danymi i wykonywanymi operacjami.

Napiszmy więc program, który będzie pobierał dane z pliku tekstowego znak po znaku.

#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{
    FILE* plik; //uchwyt do pliku

    plik = fopen("plik.txt", "r"); //otwieramy plik w trybie tylko do odczytu - parametr "r"

    char znak;

    do
    {
        znak = fgetc(plik); //zapisuję jeden znak z pliku
        cout << znak << endl; //wypsiuję na ekran
    }
    while(znak != EOF); //End Of File - koniec pliku

    fclose(plik); //zamykamy plik

    return 0;
}

Funkcja fopen(„plik”, „trybOtwarcia”); może otwierać pliki w różnych trybach, na przykład do odczytu lub zapisu. Sposób działania tej funkcji omówiłem w poprzednim akapicie „Otwieranie pliku za pomocą funkcji fopen()„.

fgets()

Funkcja fgets() odczytuje dane z wybranego wejścia (na przykład pliku) do momentu napotkania znaku nowej linii bądź do momentu wczytania określonej liczby znaków.

Przykład:

#include <stdio.h>

using namespace std;

int main()
{
   FILE *plik;
   char wczytaneZnaki[10];

   plik = fopen("plik.txt", "r"); //otwarcie pliku
   
   fgets(wczytaneZnaki, 10, plik);

   for(int i = 0;i<10;i++)
        cout << wczytaneZnaki[i];
    
   fclose(plik); //zamknięcie pliku
  
   return 0;
}

Ogólna składnia funkcji fgets():

fgets(obiektDoKtoregoZapisujemyDane, maksymalnaLiczbaZnakow, wejscie);

fscanf()

fscanf() działa bardzo podobnie do scanf(). Funkcję fscanf() można jednak wykorzystać do odczytania danych z pliku. Przyjrzyjmy się więc jak to zrobić.

Przykład:

#include <stdio.h>

using namespace std;

int main ()
{
  char wczytywaneZnaki[10];
  FILE *plik;

  plik = fopen("plik.txt", "a+");
  fscanf(plik, "%s", wczytywaneZnaki);
  fclose(plik); //zamknięcie pliku
  
  for(int i = 0;i<10;i++)
      cout << wczytywaneZnaki[i];

  return 0;
}

Ogólna składnia:

fscanf(wejscie, specyfikator, obiektWyjscia);

W miejscu specyfikator podajemy dane z poniżej tabelki:

SpecyfikatorOpis
%d lub %iLiczba całkowita ze znakiem (system dziesiętny) np. int
%fLiczba rzeczywista (system dziesiętny) np. float
%uLiczba całkowita bez znaku (system dziesiętny)
%eLiczba w notacji naukowej – ze znakiem e (małe litery)
%ELiczba w notacji naukowej – ze znakiem E (duże litery)
%gLiczba rzeczywista w notacji %f lub %e
%GLiczba rzeczywista w notacji %f lub %E
%oLiczba w systemie ósemkowym
%xLiczba w systemie szesnastkowym (małe litery)
%XLiczba w systemie szesnastkowym (duże litery)
%cZnak np. zmienne typu char
%sŁańcuch znaków zakończony “\0“, np. zmienne typu string
%pAdres pamięci

fread()

Napiszmy teraz program, który odczyta nam dane z pliku binarnego.

#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{
    FILE* plik;

    plik = fopen("plik.dat", "rb"); //otwarcie pliku jako plik binarny - parametr "b"

    int liczba;

    fread(&liczba, sizeof(int), 1, plik); //fread(wskaźnik na zmienną do której zapisujemy dane, rozmiar elementu, ilość liczb do odczytu, plik na którym wykonujemy operację);
    cout << liczba << endl; //wypisz dane

    fclose(plik); //zamykamy plik

    return 0;
}

W powyższym programie do odczytu danych binarnych została wykorzystana funkcja fread();, której składnia wygląda następująco:

fread(wskaznik_na_zmienna_do_ktorej_zapisujemy_dane, rozmiar_elementu, ilosc_liczb_do_oczytu, plik_na_ktorym_wykonujemy_operacje);

Jak widać nie ma w tym nic trudnego.

Fot: Alexandre Buisse (Nattfodd).

Spodobało się?

Jeśli tak, to zarejestruj się do newslettera aby otrzymywać informacje nowych artykułach oraz akcjach edukacyjnych. Gwarantuję 100% satysfakcji i żadnego spamowania!

, , , , , , , , , , , ,

Dodaj komentarz

Komentarze (18)

  • W fopen określamy nie tylko tryb dostępu do pliku, ale również rodzaj pliku – domyślnie otwierany jest tryb tekstowy, należałoby dodac 'b’, aby był tryb binarny

    Do wczytywania danych w c masz jeszcze fgets i fscanf, nie tylko fgetc
    natomiast w fstream nie tylko jest getline.

    Dodatkowo fstream nie do końca jest uchwytem, jest całym obiektem z mnogością metod (nie omijając operatorów <>)

  • Pola pisze:

    Obsługa plików w C++ nie jest tak bardzo skomplikowana jak mogło by się wydawać początkującym programistOM!!

  • do
    {
    getline(uchwyt, linia); //pobierz linijkę
    cout << linia << endl; //wypisz na ekranie
    }
    while(linia == ""); //przerwij jeżeli linia będzie pusta (dane w pliku się skończą)

    Pyt.: Czy ten warunek while (linia == "") nie oznacza "powtarzaj pętelę jeżeli linia jest pusta"? Nie rozumiem dlaczego taki warunek miałby oznaczać, że w linii coś się znajduje. Ktoś wyjaśni?

    • lukas124 pisze:

      Faktycznie tam powinno być while(linia != „”), wtedy mamy false w momencie, w którym trafimy na pustą linijkę – ważne jest, żeby taka była na końcu bo inaczej program będzie się wykonywał w nieskończoność.

  • Justyna xD pisze:

    Czy wie ktoś jak odczytać jaki jest AUTOR/WŁAŚCICIEL pliku w C?

    • lukas124 pisze:

      Spróbuj tak:

      #include
      #include
      #include
      #include
      #include
      #include
      #include

      using namespace std;

      void printStat(const char *, struct stat *);

      int main(int argc, char ** argv)
      {
      if (argc > 1)
      {
      struct stat buf;
      for (int i = 1; i < argc; ++i)
      {
      lstat(argv[i], &buf);
      printStat(argv[i], &buf);
      }
      }

      return 0;
      }

      void printStat(const char * fname, struct stat *data)
      {
      cout << dec << "Wlasciciel: " <st_uid << "n";
      }

  • Robert pisze:

    Może pytanie dość naiwne, ale muszę ze względu że czas mnie goni z projektem.
    Do rzeczy, jaka jest różnica w odczytywaniu plików .docx a .txt. Próbuję wykonać projekt który będzie obliczał funkcje skrótu dla tekstu z pliku. Wczytuję plik .txt z tekstem „hello world” i po wywołaniu funkcji dostaję pewny ciąg (skrót tego tekstu) natomiast wynik dla tego samego tekstu w pliku .docx jest inny. Wygląda to na złe odczytanie treści pliku, więc proszę o jakieś sugestię jak obsłużyć takie rozszerzenie

    • Cześć Robert,

      Różnica jest taka, że plik txt odczytywany podanymi w artykule metodami, zwraca dokładnie taki tekst, jaki w nim zapiszesz. Plik docx (Worda) nie składa się TYLKO z tekstu, jaki wpisałeś w edytorze. Zawiera on szereg innych danych. Aby to zobaczyć, zmień rozszerzenie docx na txt i otwórz plik dowolnym edytorem. Z tego względu dalsze operacje nie działają, tak jak oczekujesz.

      Pozdrawiam,
      Łukasz Dudziński, autor bloga Strefakodera.pl

Odpowiedz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Pin It on Pinterest