Operacje na plikach

Opis: W tym temacie wyjaśniono działanie operacji na plikach w języku C++. Zawarto również przykłady zastosowań, które pokazują, jak otwierać, zapisywać, odczytywać, modyfikować oraz usuwać pliki, umożliwiając efektywne zarządzanie danymi przechowywanymi na dysku.

Wyjaśnienie operacji na plikach

Operacje na plikach obejmują zestaw działań umożliwiających przechowywanie, odczytywanie, modyfikowanie i usuwanie danych w plikach zapisanych na dysku. Kluczowe operacje to:

  1. Otwarcie pliku – zanim plik może być używany, należy go otworzyć, określając tryb dostępu (np. tylko do odczytu, do zapisu, do dopisywania).

  2. Odczyt z pliku – umożliwia pobranie danych z pliku do pamięci programu. Odczyt może odbywać się znak po znaku, linia po linii lub w postaci binarnej.

  3. Zapis do pliku – pozwala na umieszczenie danych w pliku, co może nadpisać istniejącą zawartość lub dopisać nowe dane na końcu pliku.

  4. Zamknięcie pliku – po zakończeniu operacji na pliku należy go zamknąć, aby zwolnić zasoby systemowe.

  5. Obsługa błędów – operacje na plikach mogą się nie powieść z różnych powodów (np. brak dostępu, nieistniejący plik), dlatego należy sprawdzać status operacji.

  6. Usuwanie i zmiana nazwy pliku – pozwala na zarządzanie plikami poprzez ich kasowanie lub modyfikację nazwy.

Operacje na plikach są powszechnie wykorzystywane w aplikacjach do przechowywania danych użytkownika, konfiguracji programów, logowania zdarzeń czy przetwarzania dużych zbiorów danych.

Zastosowanie operacji na plikach w C++

Otwarcie pliku

Aby pracować z plikami w C++, należy użyć biblioteki <fstream>, która umożliwia operacje wejścia i wyjścia na plikach. Do otwarcia pliku wykorzystuje się obiekty ifstream (dla odczytu) i ofstream (dla zapisu), ewentualnie fstream (dla odczytu i zapisu).

#include <fstream>
using namespace std;

ifstream plikOdczyt("dane.txt");  // Otwarcie pliku do odczytu
ofstream plikZapis("wyniki.txt"); // Otwarcie pliku do zapisu

Zapis do pliku

Aby zapisać dane do pliku, wystarczy użyć operatora <<, podobnie jak w przypadku cout.

ofstream plik("wyniki.txt"); 
plik << "To jest zapisany tekst." << endl;
plik.close();  // Zamknięcie pliku po zakończeniu operacji

Odczyt z pliku

Dane można odczytywać przy użyciu operatora >> (dla pojedynczych wartości) lub metody getline() (dla całych linii tekstu).

ifstream plik("dane.txt");
string linia;

while (getline(plik, linia)) {
    cout << linia << endl;
}
plik.close();

Odczyt całej zawartości pliku za pomocą eof()

Możemy odczytać plik aż do jego końca, wykorzystując eof(), który zwraca true, gdy osiągniemy koniec pliku.

ifstream plik("dane.txt");
string linia;

while (!plik.eof()) {
    getline(plik, linia);
    cout << linia << endl;
}
plik.close();

Sprawdzanie poprawności otwarcia pliku

Aby uniknąć błędów, warto sprawdzić, czy plik został poprawnie otwarty.

ifstream plik("nieistniejacy.txt");
if (!plik) {
    cout << "Błąd otwarcia pliku!" << endl;
} else {
    cout << "Plik otwarty poprawnie." << endl;
}

Poruszanie się po pliku: seekg() i seekp()

Funkcje seekg() (dla odczytu) i seekp() (dla zapisu) pozwalają na przemieszczanie wskaźnika odczytu/zapisu w pliku.

fstream plik("dane.txt", ios::in | ios::out);

// Przemieszczenie wskaźnika odczytu na 10. bajt od początku pliku
plik.seekg(10, ios::beg); 

// Przemieszczenie wskaźnika zapisu na koniec pliku
plik.seekp(0, ios::end); 

plik.close();

Usuwanie i zmiana nazwy pliku

Można również usuwać pliki (remove()) i zmieniać ich nazwy (rename()).

remove("staryPlik.txt");  
rename("plikTymczasowy.txt", "nowaNazwa.txt");

Podsumowanie

Operacje na plikach w C++ pozwalają na trwałe przechowywanie i przetwarzanie danych. Możemy otwierać pliki w różnych trybach, odczytywać i zapisywać dane, poruszać się po pliku, sprawdzać błędy oraz zarządzać plikami.

Przykłady zastosowań operacji na plikach

Przykład 1 - Zapisywanie i odczytywanie danych z pliku

W tym przykładzie zademonstrowano, jak otworzyć plik, zapisać do niego dane, a następnie odczytać jego zawartość w języku C++.

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    // Tworzenie i zapis do pliku
    ofstream plikZapis("dane.txt"); // Otwarcie pliku do zapisu
    if (!plikZapis) {
        cout << "Blad otwarcia pliku do zapisu!" << endl;
        return 1;
    }
    
    plikZapis << "Jan Kowalski" << endl;
    plikZapis << "28" << endl;
    plikZapis.close(); // Zamkniecie pliku po zakonczeniu zapisu

    // Odczyt z pliku
    ifstream plikOdczyt("dane.txt"); // Otwarcie pliku do odczytu
    if (!plikOdczyt) {
        cout << "Blad otwarcia pliku do odczytu!" << endl;
        return 1;
    }
    
    string imie, nazwisko;
    int wiek;
    
    plikOdczyt >> imie >> nazwisko >> wiek; // Odczytanie danych
    plikOdczyt.close(); // Zamkniecie pliku po zakonczeniu odczytu

    // Wyswietlenie odczytanych danych
    cout << "Dane odczytane z pliku:" << endl;
    cout << "Imie: " << imie << ", Nazwisko: " << nazwisko << ", Wiek: " << wiek << endl;

    return 0;
}

Działanie:

  1. Otwarcie pliku i zapis danych
    Program tworzy plik dane.txt i zapisuje do niego przykładowe dane: imię, nazwisko oraz wiek użytkownika. Po zakończeniu zapisu plik zostaje zamknięty.

  2. Otwarcie pliku do odczytu
    Plik dane.txt jest otwierany w trybie odczytu. Program sprawdza, czy udało się go poprawnie otworzyć.

  3. Odczyt danych z pliku
    Z pliku wczytywane są imię, nazwisko i wiek użytkownika, a następnie plik zostaje zamknięty.

  4. Wyświetlenie odczytanych informacji
    Program wypisuje na ekranie odczytane dane w uporządkowanej formie.

Wynik działania programu:

Dane odczytane z pliku:
Imie: Jan, Nazwisko: Kowalski, Wiek: 28

Podsumowanie:

Ten przykład pokazuje, jak można zapisywać i odczytywać dane z pliku w języku C++. Obsługa plików jest kluczowa w programowaniu, ponieważ umożliwia trwałe przechowywanie i przetwarzanie informacji.

Przykład 2 - Dopisywanie danych do pliku i odczyt całej zawartości

W tym przykładzie zademonstrowano, jak dopisać nowe dane do istniejącego pliku i odczytać całą jego zawartość.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
    // Otwarcie pliku w trybie dopisywania
    ofstream plikZapis("dane.txt", ios::app); // Tryb ios::app dopisuje dane na koncu pliku
    if (!plikZapis) {
        cout << "Blad otwarcia pliku do zapisu!" << endl;
        return 1;
    }
    
    // Dopisanie kolejnych danych do pliku
    plikZapis << "Anna Nowak" << endl;
    plikZapis << "24" << endl;
    plikZapis.close(); // Zamkniecie pliku po zakonczeniu zapisu

    // Odczyt calej zawartosci pliku linia po linii
    ifstream plikOdczyt("dane.txt"); // Otwarcie pliku do odczytu
    if (!plikOdczyt) {
        cout << "Blad otwarcia pliku do odczytu!" << endl;
        return 1;
    }

    cout << "Zawartosc pliku:" << endl;
    string linia;
    
    while (getline(plikOdczyt, linia)) { // Odczyt kazdej linii az do konca pliku
        cout << linia << endl;
    }

    plikOdczyt.close(); // Zamkniecie pliku po odczycie

    return 0;
}

Działanie:

  1. Dopisanie nowych danych do pliku

    • Plik dane.txt jest otwierany w trybie dopisywania (ios::app), dzięki czemu nowe dane nie nadpisują istniejącej zawartości, a są dodawane na końcu.

    • Dopisywane są kolejne informacje: "Anna Nowak" i "24".

  2. Odczytanie całej zawartości pliku

    • Plik jest otwierany w trybie odczytu, a program sprawdza, czy otwarcie było udane.

    • Zawartość pliku jest odczytywana linia po linii za pomocą getline() aż do końca pliku (EOF).

  3. Wyświetlenie danych

    • Program wypisuje zawartość pliku na ekran.

Wynik działania programu:

Jeśli dane.txt przed uruchomieniem programu zawierało:

Jan Kowalski
28

to po wykonaniu programu jego nowa zawartość będzie:

Jan Kowalski
28
Anna Nowak
24

a wynik wyświetlony na ekranie:

Zawartość pliku:
Jan Kowalski
28
Anna Nowak
24

Podsumowanie:

Ten przykład pokazuje, jak można dopisywać dane do pliku bez ich nadpisywania oraz jak odczytać całą jego zawartość. Jest to szczególnie przydatne, gdy chcemy rejestrować historię danych, np. w dziennikach zdarzeń lub listach użytkowników.

Przykład 3 - Poruszanie się po pliku za pomocą seekg() i seekp()

W tym przykładzie zademonstrowano, jak poruszać się po pliku przy użyciu funkcji seekg() i seekp(), które pozwalają na zmianę pozycji kursora odczytu i zapisu.

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    // Tworzenie i zapis do pliku
    fstream plik("dane.bin", ios::out | ios::binary);
    if (!plik) {
        cout << "Blad otwarcia pliku do zapisu!" << endl;
        return 1;
    }

    // Zapisanie liczb do pliku binarnego
    int liczby[] = {10, 20, 30, 40, 50};
    plik.write(reinterpret_cast<char*>(liczby), sizeof(liczby));
    plik.close(); // Zamkniecie pliku po zapisie

    // Otworzenie pliku do odczytu
    fstream plikOdczyt("dane.bin", ios::in | ios::binary);
    if (!plikOdczyt) {
        cout << "Blad otwarcia pliku do odczytu!" << endl;
        return 1;
    }

    int liczba;
    
    // Przesunięcie kursora na trzecia liczbe (indeks 2)
    plikOdczyt.seekg(2 * sizeof(int), ios::beg);  
    plikOdczyt.read(reinterpret_cast<char*>(&liczba), sizeof(int));

    cout << "Trzecia liczba w pliku: " << liczba << endl;

    plikOdczyt.close(); // Zamkniecie pliku po odczycie

    return 0;
}

Działanie programu:

  1. Zapis do pliku binarnego:

    • Program tworzy plik dane.bin i zapisuje w nim tablicę liczb {10, 20, 30, 40, 50} w formie binarnej.

    • Dane są zapisywane za pomocą write().

  2. Poruszanie się po pliku:

    • Plik jest ponownie otwierany w trybie odczytu binarnego.

    • Kursor odczytu jest przesuwany za pomocą seekg() na trzecią liczbę (2 * sizeof(int), ponieważ indeksy zaczynają się od 0).

    • Program odczytuje tę liczbę za pomocą read() i wyświetla ją na ekranie.

  3. Wyświetlenie wyniku:

    • Program wypisuje wartość trzeciej liczby zapisanej w pliku.

Wynik działania programu:

Trzecia liczba w pliku: 30

Podsumowanie:

Ten przykład pokazuje, jak można manipulować pozycją kursora w pliku za pomocą seekg() (dla odczytu) i seekp() (dla zapisu). Jest to przydatne w pracy z plikami binarnymi, gdzie konieczne jest szybkie przechodzenie do określonych pozycji w pliku.

Przykład 4 - Usuwanie i zmiana nazwy pliku

W tym przykładzie zademonstrowano, jak usunąć plik oraz zmienić jego nazwę przy użyciu funkcji remove() i rename().

#include <iostream>
#include <cstdio> // Biblioteka do operacji na plikach (remove, rename)

using namespace std;

int main() {
    const char* nazwaPliku = "przykladowy.txt";
    const char* nowaNazwaPliku = "zmieniona_nazwa.txt";

    // Tworzenie pliku testowego
    FILE* plik = fopen(nazwaPliku, "w");
    if (plik) {
        fputs("To jest testowy plik.\n", plik);
        fclose(plik);
        cout << "Plik '" << nazwaPliku << "' zostal utworzony." << endl;
    } else {
        cout << "Blad podczas tworzenia pliku!" << endl;
        return 1;
    }

    // Zmiana nazwy pliku
    if (rename(nazwaPliku, nowaNazwaPliku) == 0) {
        cout << "Plik zostal pomyslnie zmieniony na '" << nowaNazwaPliku << "'." << endl;
    } else {
        cout << "Blad podczas zmiany nazwy pliku!" << endl;
        return 1;
    }

    // Usuniecie pliku
    if (remove(nowaNazwaPliku) == 0) {
        cout << "Plik '" << nowaNazwaPliku << "' zostal usuniety." << endl;
    } else {
        cout << "Blad podczas usuwania pliku!" << endl;
        return 1;
    }

    return 0;
}

Działanie programu:

  1. Tworzenie pliku:

    • Program otwiera plik "przykladowy.txt" w trybie zapisu ("w").

    • Zapisuje w nim przykładowy tekst.

    • Zamykany plik po zapisie.

  2. Zmiana nazwy pliku:

    • Używana jest funkcja rename(), która zmienia nazwę "przykladowy.txt" na "zmieniona_nazwa.txt".

    • W przypadku błędu wyświetlany jest komunikat.

  3. Usuwanie pliku:

    • Funkcja remove() usuwa plik "zmieniona_nazwa.txt".

    • Jeśli operacja się powiedzie, wyświetlany jest odpowiedni komunikat.

Wynik działania programu:

Plik 'przykladowy.txt' zostal utworzony.
Plik zostal pomyslnie zmieniony na 'zmieniona_nazwa.txt'.
Plik 'zmieniona_nazwa.txt' zostal usuniety.

Podsumowanie:

Ten przykład ilustruje, jak w C++ można programowo zmieniać nazwy plików oraz je usuwać. Funkcje rename() i remove() należą do standardowej biblioteki C i mogą być używane do podstawowych operacji na plikach w systemie plików.

Zadania - operacje na plikach w C++

Zadanie 1 - Podstawowe operacje na plikach w C++

Napisz program w C++, który wykonuje podstawowe operacje na plikach. Program będzie odczytywał dane z pliku i wyświetlał je na ekranie.

Kroki do wykonania:

  1. Stwórz plik tekstowy dane.txt, który będzie zawierał następujące dane:

    Jan Kowalski 25
    Anna Nowak 30
    Piotr Zieliński 28
  2. Zdefiniuj zmienne do przechowywania danych odczytanych z pliku: imie, nazwisko, wiek.

  3. Otwórz plik dane.txt w trybie odczytu.

  4. Odczytaj dane z pliku i zapisz je do zmiennych.

  5. Wyświetl dane na ekranie.

Wynik działania programu:

Imię: Jan, Nazwisko: Kowalski, Wiek: 25
Imię: Anna, Nazwisko: Nowak, Wiek: 30
Imię: Piotr, Nazwisko: Zieliński, Wiek: 28

Zadanie 2 - Tworzenie, usuwanie i zmiana nazwy pliku

Napisz program w C++, który pozwala użytkownikowi na trzy operacje na plikach:

  • utworzenie nowego pustego pliku,

  • usunięcie istniejącego pliku,

  • zmianę nazwy pliku.

Kroki do wykonania:

  1. Zapytaj użytkownika, jaką operację chce wykonać:

    • 1 - Utworzyć nowy plik,

    • 2 - Usunąć istniejący plik,

    • 3 - Zmienić nazwę pliku.

  2. Jeśli użytkownik wybierze utworzenie pliku:

    • Poproś o nazwę nowego pliku.

    • Utwórz pusty plik przy użyciu ofstream.

    • Zamknij plik i wyświetl komunikat o powodzeniu.

  3. Jeśli użytkownik wybierze usunięcie pliku:

    • Poproś o nazwę pliku do usunięcia.

    • Sprawdź, czy plik istnieje.

    • Jeśli istnieje, usuń go za pomocą remove().

    • Wyświetl komunikat o powodzeniu lub błędzie.

  4. Jeśli użytkownik wybierze zmianę nazwy pliku:

    • Poproś o aktualną nazwę pliku i nową nazwę.

    • Sprawdź, czy plik istnieje.

    • Jeśli istnieje, zmień jego nazwę za pomocą rename().

    • Wyświetl komunikat o powodzeniu lub błędzie.

Przykład działania programu:

Wybierz operację:
1 - Utwórz nowy plik
2 - Usuń plik
3 - Zmień nazwę pliku
Twój wybór: 1

Podaj nazwę nowego pliku: nowy_plik.txt

Plik 'nowy_plik.txt' został utworzony.
Wybierz operację:
1 - Utwórz nowy plik
2 - Usuń plik
3 - Zmień nazwę pliku
Twój wybór: 2

Podaj nazwę pliku do usunięcia: dane.txt

Plik 'dane.txt' został usunięty.
Wybierz operację:
1 - Utwórz nowy plik
2 - Usuń plik
3 - Zmień nazwę pliku
Twój wybór: 3

Podaj nazwę pliku do zmiany: stare_dane.txt
Podaj nową nazwę pliku: archiwum.txt

Plik został pomyślnie zmieniony na 'archiwum.txt'.

Zadanie 3 - Tworzenie pliku i dopisywanie danych

Napisz program w C++, który tworzy plik tekstowy, zapisuje do niego dane o osobach, a następnie umożliwia dopisanie nowych danych.

Kroki do wykonania:

  1. Sprawdź, czy plik dane.txt istnieje.

    • Jeśli nie istnieje, utwórz go i zapisz przykładowe dane:

      Jan Kowalski 25
      Anna Nowak 30
    • Jeśli plik istnieje, dopisz do niego kolejne osoby.

  2. Zdefiniuj strukturę Osoba, która będzie przechowywać: imie, nazwisko, wiek.

  3. Zapytaj użytkownika, czy chce dopisać nową osobę do pliku.

    • Jeśli tak, pobierz dane od użytkownika i dopisz je do pliku.

  4. Wyświetl zawartość pliku po dopisaniu nowych danych.

Przykład działania programu:

Plik dane.txt nie istnieje. Tworzenie pliku i zapis przykładowych danych...
Czy chcesz dodać nową osobę? (t/n): t
Podaj imię: Piotr
Podaj nazwisko: Zieliński
Podaj wiek: 28

Dane w pliku po dopisaniu:
Imię: Jan, Nazwisko: Kowalski, Wiek: 25
Imię: Anna, Nazwisko: Nowak, Wiek: 30
Imię: Piotr, Nazwisko: Zieliński, Wiek: 28