Podrozdziały


16.7 Pliki wewnętrzne

Rolę plików mogą też pełnić napisy, czyli tablice znaków w stylu C i napisy w stylu C++, a więc obiekty klasy string.


16.7.1 Tablice znaków jako pliki wewnętrzne

Napis w stylu C jest ciągłym obszarem pamięci, do którego odnosimy się jak do tablicy znaków. Obszar ten może być traktowany jako plik, do którego dane mogą być zapisywane lub z którego mogą być odczytywane.

Aby korzystać z tego rodzaju „plików”, należy dołączyć plik nagłówkowy strstream, który daje nam dostęp do klasy strumieniowej wejściowej istrstream i wyjściowej ostrstream.

Ten nagłówek został usunięty ze standardu, ale jest implementowany przez wszystkie kompilatory C++ dla zachowania wstecznej zgodności. Przy kompilacji mogą pojawić się ostrzeżenia!

Obiekt strumieniowy klasy wyjściowej ostrstream tworzymy na dwa sposoby:

Przykład:


P128: intfilo.cpp     Zapis do plików wewnętrznych

      1.  #include <iostream>
      2.  #include <strstream>
      3.  #include <cstdlib>   // free
      4.  using namespace std;
      5.  
      6.  int main() {
      7.      // wersja "gumowa"
      8.      ostrstream napis1;
      9.      napis1 << "Poczatek, " << "dalszy ciag, "
     10.             << "koniec."    << ends;
     11.      char* n = napis1.str();
     12.      cout << "Napis jest: " << n << endl;
     13.      free(n);
     14.  
     15.      // wersja tablicowa
     16.      char tab[30];
     17.      ostrstream napis2(tab,sizeof(tab));
     18.      napis2 << "Magda " << "Kasia " << "Marta" << ends;
     19.      cout << tab << endl;
     20.  }

Program ten wypisuje na ekranie
    Napis jest: Poczatek, dalszy ciag, koniec.
    Magda Kasia Marta
Zauważmy, że pamięci na napis n nie alokujemy. Jest ona alokowana automatycznie i jej adres jest zwracany przez metodę str (linia 11).

Podobnie można z tablicy znaków czytać, tworząc obiekt klasy istrstream.

Pliki wewnętrzne oparte na C-napisach są czasem używane do reprezentowania pliku dyskowego, szczególnie jeśli zachodzi potrzeba częstego „skakania” do różnych części pliku, co może być drogie, gdyż wymaga wielu operacji dostępu do pliku. Może wtedy być bardziej opłacalne wczytanie całego pliku do tablicy znaków i dalej używanie jej jak pliku wewnętrznego.


16.7.2 Napisy C++ jako pliki wewnętrzne

Podobnie jak tablice znaków, do reprezentowania plików wewnętrznych mogą być używane obiekty klasy string. Jest to łatwiejsze i bezpieczniejsze niż używanie tablic znaków.

Aby korzystać z tego udogodnienia, należy dołączyć, prócz pliku string, plik nagłówkowy sstream. Zdefiniowane tam są klasy strumieniowe wejściowa istringstream i wyjściowa ostringstream korzystające z napisów klasy string.

Strumień wyjściowy można utworzyć za pomocą konstruktora domyślnego:

       ostringstream strm;
i pisać do niego jak do normalnego strumienia
       strm << "To be" << " or not to be" << ", etc.";
Nie trzeba martwić się o przepełnienie, bo pamięć w miarę potrzeby jest alokowana automatycznie. Po zakończeniu pisania do strumienia, wywołujemy na jego rzecz metodę str, która zwraca napis (obiekt klasy string) zawierający rezultat, na przykład:
       string s = strm.str();
       cout << s << endl;
Można też skonstruować strumień z wpisanym już fragmentem w trybie dopisywania na końcu
       ostringstream ostr("Jakis napis", ios::ate);
       ostr << "Dalsza czesc";
a następnie dopisywać dalsze fragmenty, jak w przykładzie powyżej.

Istniejący obiekt klasy string też może być otwarty jako wejściowy plik wewnętrzny, jak w przykładzie poniżej:


P129: intstr.cpp     Napisy C++ jako pliki wewnętrzne

      1.  #include <iostream>
      2.  #include <sstream>
      3.  using namespace std;
      4.  
      5.  void words(const string& s) {
      6.      istringstream istr(s);
      7.  
      8.      string word;
      9.      while ( istr >> word )
     10.          cout << word << endl;
     11.  }
     12.  
     13.  int main() {
     14.      string s = "Bach Haydn";
     15.      ostringstream ostr(s, ios::ate);
     16.      ostr << " Chopin";
     17.      string s1 = ostr.str();
     18.      words(s1);
     19.  }

Najpierw, w linii 15, otwieramy wewnętrzny plik wyjściowy zainicjowany zawartością napisu s. Dodajemy do niego pewne dane (linia 16) i pobieramy wynikową zawartość do s1. Następnie s1 jest przekazywane do funkcji words, która ten napis otwiera do czytania jako wejściowy plik wewnętrzny (linia 6). Z pliku tego czytamy kolejne słowa oddzielone znakiem odstępu, według normalnych zasad czytania ze strumienia. Zauważmy, że po osiągnięciu końca pliku, stan strumienia przejdzie w  bad, co zakończy pętlę z linii 9-10. Program drukuje zatem
    Bach
    Haydn
    Chopin

T.R. Werner, 25 lutego 2017; 22:31