C++/Strumienie

Z Wikibooks, biblioteki wolnych podręczników.
< C++
Skocz do: nawigacja, szukaj

Czym są strumienie?[edytuj]

Najprościej mówiąc jest to ciąg bajtów o nieokreślonej długości. Działanie strumieni zademonstruje na przykładzie kranu, za pomocą którego nalewamy wodę do szklanki. Gdy nasz program chce wyświetlić coś na ekranie (lub zapisać coś do pliku) to musi on "przesłać" wodę do kranu. Szklanka (ekran) ma ograniczoną pojemność i najpierw trzeba ją opróżnić by przyjąć kolejne porcje. Nie przejmuj się, jeśli nie zrozumiałeś powyższej analogii, wszystko przyjdzie z czasem.

Zarządzać strumieniami możemy tak samo, jak w języku C, za pomocą struktur typu FILE i poleceń fopen() i fclose(), lecz daje to małe możliwości, o czym się przekonamy podczas nauki programowania obiektowego. Dlatego w C++ utworzono dużo wygodniejszy mechanizm, z którego już skorzystaliśmy. Wyróżniamy trzy rodzaje strumieni:

Strumienie "konsoli"[edytuj]

Zapewne każdy uważny czytelnik wie już, jak pobierać oraz wyświetlać dane na ekranie konsoli. Dla przypomnienia napiszę. Do wczytywania danych ze strumienia wejścia służy operator >>, a wysyłania danych do strumienia wyjścia służy operator <<. Jednak metody, które do tej pory poznałeś nie zawsze spełnią twoje oczekiwania. Jak myślisz, co wyświetli poniższy program?

#include <iostream>
#include <string>

int main ()
{
   std::string x;
   std::cout << "Podaj swoje imie i nazwisko: ";
   std::cin >> x;
   std::cout << x << std::endl;
   return 0;
}

Prawdopodobnie Cię rozczaruję - wyświetli tylko i wyłącznie imię! Operator >> "wyciąga" pojedyncze słowo oddzielone białymi znakami oraz zapisuje je do zmiennej x. Musimy stworzyć kolejną zmienną typu string i zapisać w niej nazwisko i użyć kaskadowej operacji wstawiania danych do strumienia. Wystarczy dokonać kilka modyfikacji tego programu:

  • zmienić linijkę:
std::string x;

na:

std::string a, b;
  • zmienić linijkę:
std::cin >> x;

na

std::cin >> a >> b;
  • zmienić linijkę:
std::cout << x << std::endl;

na

std::cout << a << ' ' << b << std::endl;

Obiekty tego typu dziedziczą po klasie ostream dla strumieni wyjścia i istream dla wejścia. Plik nagłówkowy iostream sprawia, że mamy od początku otwarte 3 strumienie:

  • std::cin - standardowe wejście
  • std::cout - standardowe wyjście
  • std::cerr - gdy coś złego się stanie (wyjście)

Funkcja "getline"[edytuj]

Funkcja ta umożliwia pobranie z klawiatury tekstu zawierającego spacje (obiekt "cin" przestaje wczytywać tekst po napotkaniu pierwszej spacji, tabulatora lub znaku końca wiersza). Oto przykład użycia funkcji "getline":

#include <iostream>
#include <string>

using namespace std;

int main()
{
   cout << "Podaj tekst: ";
   string tekst;
   getline(cin, tekst);
   cout << tekst << endl;
}

Jeśli przed użyciem funkcji "getline" użyjemy obiektu "cin", ten ostatni pozostawia zwykle znak końca wiersza '\n' w buforze klawiatury. Funkcja "getline" napotykając ten znak natychmiast kończy działanie, więc żeby uniknąć błędnego działania programu, należy wywołać funkcję cin.ignore(). Zostało pokazane to w poniższym przykładzie:

#include <iostream>
#include <string>

using namespace std;

int main()
{

    cout << "Podaj liczbę: ";
    int liczba;
    cin >> liczba;
    
    cout << "Podaj tekst: ";
    string tekst;
    cin.ignore(); // to wywołanie usunie z bufora znak '\n' pozostawiony przez obiekt "cin"
    getline(cin, tekst);
    
    cout << liczba << ' ' << tekst << endl;

    return 0;
}

Strumienie plikowe[edytuj]

Program w C++ zapisujący dane do pliku graficznego

Za pomocą strumieni możemy czytać i zapisywać do plików:

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

int main()
{
   std::string a;
   std::cout << "Nacisnij Enter aby zakonczyc zapis.\n";
   std::ofstream f ("log.txt");
   std::cin >> a;
   if (f.good())
   {
      f << a;
      f.close();
   }
   return 0;
}

Program zapisuje łańcuch znaków do pliku. Pobiera go do momentu naciśnięcia Enter.


Inny przykład :

Jak utworzyć plik ppm za pomocą stumeinai plikowego
/*
https://commons.wikimedia.org/wiki/File:XOR_texture.png

g++ p.cpp -Wall
./a.out

*/


#include <fstream>

int main()
{
	std::ofstream file;
	file.open("xor.ppm");
	file << "P2 256 256 255\n";
	for (int i = 0; i < 256; i++)
		for (int j = 0; j < 256; j++)
			file << (i ^ j) << ' ';
	file.close();
	return 0;
}

Strumienie napisów[edytuj]

Wyróżniamy jeszcze jeden rodzaj strumieni - stringstream. Dzięki niemu jesteśmy w stanie operować na napisach tak, jak na zwykłym strumieniu. Wyobraźmy sobie sytuację, gdy musimy zamienić liczbę całkowitą na napis. Język C umożliwiał nam dokonywanie takich operacji za pomocą funkcji sprintf() bądź niestandardowej funkcji itoa(). Jednak zaprezentowane poniżej rozwiązanie jest o wiele czytelniejsze.

#include <iostream>
#include <sstream>

int main ()
{
   long x;   // Zmienna do przechowania liczby
   std::string napis;   // Zmienna do przechowania napisu
   std::stringstream ss;  // Strumień do napisów

   std::cout << "Podaj dowolna liczbe calkowita: ";
   std::cin >> x;

   ss << x;   // Do strumienia 'wysyłamy' podaną liczbę
   napis = ss.str();   // Zamieniamy zawartość strumienia na napis

   std::cout << "Dlugosc napisu wynosi " << napis.size() << " znakow." << std::endl;
   return 0;
}