8 Operacje wejścia wyjścia

Strumienie wejścia-wyjścia:

wyjścia:
printf()
puts()

wejścia:
scanf()
gets()

Strumienie tekstowe są pogrupowane w wiersze tekstu (do 255 znaków w jednym wierszu) i zakończone znakiem / O (znak końca linii) .
Strumienie binarne to ciąg danych reprezentowanych przez zera i jedynki. Tego typu używa się podczas operacji na plikach.

W języku C istnieje pięć standardowych (zdefiniowanych) strumieni wejścia-wyjścia: stdi n, stdout, stderr, stdprn i stdaux:
Stdin - strumień standardowego wejścia. Korzysta z danych tekstowych
wpisanych z klawiatury.
Stdout - strumień standardowego wyjścia. Służy do przesyłania danych
tekstowych na ekran.
Stderr - strumień „standardowego błędu" . Służy do wyświetlania błędów
na ekranie komputera.
Stdprn - strumień drukarki. Służy do wysyłania danych tekstowych do
portu drukarki.
Stdaux - strumień pomocniczy. Służy do przesyłania danych do portu
COM1 .

funkcje, które pobierają dane ze standardowego wejścia (stdin ) dzielą się na:
- pobierające pojedyncze znaki z klawiatury, np . getcha r ( ) ;
- pobierające z klawiatury całe wiersze, np . gets ( ) ;
- pozwalające na manipulację strumieniami wejścia - scanf ( ) ;


Przykład odczytu znaku z klawiatury i wyświetlenia go na ekranie:
#include <stdio.h>
int znak :
int main( )
{
znak = getchar();
printf("Wpisales znak:");
putchar (znak);
printf("\n");
return O;
}


funkcja getchar() zwraca wartość typu int , a więc tylko odpowiednik znaku w kodzie ASCII. Nasza zmienna - znak - musi być zatem typu int.
Do wyświetlenia na ekranie pobranego wcześniej znaku używa się funkcji wyjścia putchar( )

Pobieranie całych wierszy, prototyp:
char *gets(char *str);

Funkcja jako argument pobiera wskaźnik do odpowiedniego łańcucha
znaków i również zwraca wskaźnik do innego łańcucha (do typu char)

Funkcją pozwalającą na manipulowanie strumieniami wejścia jest
dobrze Ci znana funkcja scanf ( ) . Mówimy, że funkcja manipuluje strumieniami,
ponieważ może interpretować pobrane wartości z klawiatury
oraz przypisywać je odpowiednim typom zmiennych. Służy do tego
tzw. łańcuch formatowania

scanf( "%d",&zmienna );


W skład każdego specyfikatora konwersji wchodzą następujące znaki:
specyfikator %d informujący o type zmiennej

-opcjonalnie liczba, która określa szerokość pola, czyli liczbę
znaków, jaką scanf( ) ma pobrać ze standardowego wejścia;
-opcjonalnie tzw. -modyfikator precyzji (z ang. precision
modificator) , który modyfikuje znaczenie specyfikatora typu
(listę modyfikatorów precyzji przedstawiono w tabeli 4 . 2 ) .

Tabela 4.2. Modyfikatory precyzji
Modyfikator precyzji Znaczenie
h  -Znak ten umieszczony przed specyfikatorami typu d, i , o, u lub x informuje funkcję o tym, że argument jest wskaźnikiem do typu s hort
l - Znak ten umieszczony przed specyfikatorami typu d, i, o, u lub x informuje funkcję o tym, że argument jest wskaźnikiem do typu long
L - Znak ten umieszczony przed specyfikatorami typu e, f lub g informuje funkcję o tym, że argument jest wskaźnikiem do typu longdouble

Program, który pobierze z klawiatury, a następnie wyświetli na ekranie liczbę pięciocyfrową (3 pierwsze cyfry powinny być zapisane w jednej zmiennej , natomiast 2 pozostałe w drugiej)
#include<stdio.h>
int liczbal,liczba 2;
char napis[30];
int main()
{
printf("\nWpisz 5-cyfrowa liczbe:");
scanf("%3d%2d",&liczbal,&liczba2);
printf("\nWpisales liczby%d i %d.\n",liczbal,liczba2);
return O;
}




Funkcje wyjścia

Funkcja putchar() wysyła pojedyncze znaki (kody ASCI) do standardowego wyjścia (na ekran) .
Prototyp funkcji putchar()

int putchar(int c);


Kolejną funkcją wyjścia jest funkcja puts(). Pozwala ona wyświetlać na ekranie całe wiersze tekstu.
Prototyp funkcji puts ( ):

int puts(char *cp);


Kopiowanie łańcuchów znaków

Funkcja strcpy() kopiuje cały łańcuch znaków (łącznie ze znakiem \0) do innego miejsca w pamięci komputera. Prototyp funkcji strcpy():

char *strcpy(char *przeznaczenie, char *zrodlo);


Program, który przekopiuje dowolny łańcuch znaków do innego łańcucha, pamiętaj o wcześniejszym zadeklarowaniu docelowego łańcucha oraz o przypisaniu mu pamięci.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char zrodlo[]="Nasz lancuch zrodlowy";
char docel1[30]; 
char *docel 2;
int main()
{
printf("\nLancuch zrodlowy: %s", zrodlo);
strcpy (docel1,zrodlo);
printf("\n pierwszy lancuch docelowy powykonaniu");
printf("operacji kopiowania: %s",docel1);
docel2=(char *)malloc(strlen(zrodlo)+l);
strcpy (docel2,zrodlo);
printf( "\ndrugi lancuch docelowy po ");
printf( "przekopiowaniu: %s \n", docel2);
return O ;
}



Drugą funkcją służącą do kopiowania łańcuchów znaków jest strncpy(). W przeciwieństwie do funkcji strcpy () funkcja strncpy () pozwala na _określenia liczby znaków, które mają być  skopiowane do miejsca przeznaczenia.
Prototyp funkcji strncpy()
char *strncpy ( char *przeznaczenie,  char *zrodlo, size_t  n  );

strncpy ( ) kopiuje pierwsze n znaków łańcucha źródłowego do miejsca przeznaczenia.


Łączenie łańcuchów znaków

Funkcjami używanymi do łączenia łańcuchów znaków są strcat() oraz strncat().

Prototyp funkcji strcat ();

char *strcat(char *lancuchl, char *lancuch2) ;
Funkcja strcat() dodaje kopię łańcucha lancuch2 na koniec łańcucha lancuch1.

Funkcja strncat ( ) jest bardzo podobna do strcat ( ) uwzględnia tylko liczbę znaków.


Operacje na plikach

Aby utworzyć plik w języku C, należy zdefiniować wskaźnik do pliku.
W pliku nagłówkowym <stdio.h> jest zdefiniowany specjalny wskaźnik do tego celu - F I LE *.
Deklaracja wskaźnika do pliku wygląda tak:

FILE *wskaznik_do_pliku;

Aby utworzyć nowy plik lub otworzyć już istniejący, używamy funkcji fopen o następującym prototypie:
FILE* fopen(const char* nazwapliku, const char*  tryb ) ;

Funkcja fopen ( ) zwraca wskaźnik do pliku lub NULL (jeśli nie można otworzyć pliku).
Następnie za pomocą tego wskaźnika można przesuwać się w obrębie pliku i odpowiednio go edytować lub odczytywać. Nazwa pliku to ścieżka do pliku lub sama nazwa pliku (jeśli plik znajduje
się w tym samym katalogu, co program wywołujący funkcję.

tryb oznacza sposób otwarcia pliku. Trzy najważniejsze tryby to:
„r" - otwarcie pliku do odczytu;
„w" - otwarcie pliku do zapisu;
„a" - otwarcie pliku w trybie dopisywania.

W celu odczytania pliku tekstowego należy użyć jednej z trzech funkcji:
fscanf, fgetc lub fgets



ODCZYTYWANIE pliku tekstowego fscanf, fgetc, fgets, fread 

fscanf działa tak jak scanf, tyle że dodajemy dodatkowo, jako pierwszy parametr, wskaźnik do pliku, który chcemy odczytać, np.:
fscanf ( wskaznik_dopliku, "%d", zmienna_int )

Takie wywołanie funkcji spowoduje odczytanie elementu z pliku jako typ int i przypisanie go do zmiennej zmienna_int

Po odczytaniu kolejnych elementów wskaźnik pliku jest odpowiednio przesuwany na miejsce, w którym kończy się dany element.
Najlepiej korzystać z funkcji fscanf, jeśli odczytujemy plik, który zawiera szczególny rodzaj danych - nie tylko tekst, ale np. liczby różnych typów. Można wtedy bezpośrednio zapisać kolejne elementy pliku do odpowiednich zmiennych

Napisz program, który wypisze na ekranie zawartość utworzonego wcześniej pliku tekstowego o nazwie plik. txt. Plik ten zawiera tylko liczby typu int oraz float zapisane jedna podrugiej. Wykorzystaj funkcję fscanf.


#include <stdio.h>
int main ()
{

int a;
FILE *plik;
float b;
if((plik = fopen (plik.txt", "r")) !=NULU)
 {
   while ( fscanf( plik, "%d %f", &a, &bl) == 2 )
   printf ("%d %f" , a , b);
 }
else
return -1;
fclose (plik);
return 0;
}


Odczytywanie pliku tekstowego fgetc

Odczytuje pojedyncze znaki, zwraca int.
Program, który wypisze zawartość pliku plik. txt na ekranie. Plik plik. txt zawiera tylko tekst


#include <stdio.h>
int main()

FILE *plik;
char c;
if ((plik=fopen(plik.txt","r"))!=NULL)
{
   while ((c=fgetc(plik) !=EOF)
   printf("%c", c):
}
else
    return - 1;

fclose(plik);
return O 
}



Odczytywanie pliku tekstowego fgets
Funkcja fgets służy do odczytywania z pliku tekstowego kolejnych łańcuchów znaków i zapisywania ich w zmiennej (char * 7 ancuch) przekazywanej jako parametr funkcji. Kolejne znaki z pliku zapełniają łańcuch aż do napotkania znaku końca linii lub zapisania liczby znaków przekazanej jako parametr ( int dlugosc) .


#include <stdio.h>
int main()
{
FILE *plik;
char lancuch[80];
if ((plik = fopen("plik.txt","r")) !=NULL)
{
   while (fgets(lancuch.sizeof(lancuch).plik) !=NULL)
   printf("%s", lancuch);
else
   return -1;
fclose (plik);
return O :
}


fread - odczytanie z pliku danych i zapisanie ich w tablicy (także odczyt plików binarnych)
fread(void *ptr, size_t size, size_t nitems, FILE *stream);



ptr 
wskaźnik na tablicę
size 
rozmiar elementu tablicy (w bajtach)
nitems 
liczba elementów do odczytania
stream 
plik, na którym wykonywana jest operacja


fread zwraca liczbe elementow do odczytania, jak skonczy zwraca 0.

przykład fread i fwrite  pod zapisywaniem



ZAPISYWANIE do pliku tekstowego.

fprintf - jak print ale do pliku
   fprintf( wskaznik_dopliku , "%d ", zmienna typu _int )
fputc - zapisuje pojedynczy znak przekazany jako int
   int fputc ( int znak , FIL E *wskaznik_dopliku)
fputs - zapisanie łańcucha znaków przekazanego jako parametr
fwrite - zapisanie do pliku danych z tablicy, plik binarny
   fwrite(void *ptr, size_t size, size_t nitems, FILE *stream); 

Przykłady:

fprintf
Napisz program, który utworzy nowy plik tekstowy o nazwie plik. txt, a następnie zapisze do niego w kolejnych liniach liczby od 0 do 10:

#include <stdio.h>
int main()
{
FILE *plik;
int i;
if ((plik=fopen("plik.txt","w")) !=NULL
{
   for ( i=O; i<=10; i++)
      if(fprintf(plik, "%d\n",i)<0)
         return -1;
}
else
   return -1;
fclose(plik);
return O:
}


fputc
Napisz program, który otworzy istniejący plik tekstowy i skopiuje jego zawartość do innego, nowo utworzonego pliku. Wykorzystaj funkcje fputc i fgetc. Nazwy pliku źródłowego i docelowego muszą zostać podane z linii poleceń.


#include <stdio.h>

int main ( int argc, char* argv[])
{
FILE *plik_zrodlowy, *plik_docelowy;
int znak;
if (argc !=3)
{
printf("Uruchomienie programu:nazwa_programu plik_zrodlowy plik_docelowy\n");
return -1;
}

if((plik_zrodlowy=fopen(argv[1],"r"))==NULL
   return -l;
if ((plik_docelowy=fopen(argv[2],"w"))==NULL
   return -l;
while ((znak=fgetc(plik_zrodlowy)) !=EOF
   fputc(znak, plik_docelowy);

fclose(plik_zrodlowy);
fclose(plik=docelowy);
return 0;
}

fputs - to samo zadanie
różnica tylko w pętli while:


#include <stdio.h>

int main ( int argc, char* argv[])
{
FILE *plik_zrodlowy, *plik_docelowy;
int znak;
if (argc !=3)
{
printf("Uruchomienie programu:nazwa_programu plik_zrodlowy plik_docelowy\n");
return -1;
}

if((plik_zrodlowy=fopen(argv[1],"r"))==NULL
   return -l;
if ((plik_docelowy=fopen(argv[2],"w"))==NULL
   return -l;

while (fgets(lancuch, sizeof(lancuch) plik_zrodlowy) !=NULL)
   fputs (launch, plik_docelowy );

fclose(plik_zrodlowy);
fclose(plik=docelowy);
return 0;
}



fwrite:
fwrite(void *ptr, size_t size, size_t nitems, FILE *stream);



ptr 
wskaźnik na tablicę
size 
rozmiar elementu tablicy
nitems 
liczba elementów do zapisania
stream 
plik, na którym wykonywana jest operacja



Napisz funkcję, która dostaje jako argumenty ścieżki dostępu do dwóch i przepisuje zawartość pierwszego pliku do drugiego pliku (stara zawartość drugiego pliku ma zostać skasowana).
Ponieważ w tekście nie jest zaznaczone, że przepisywany plik jest tekstowy, to należy go przepisać w trybie binarnym:
FREAD zwraca liczbę elementów do zapisania (tutaj 100) jak skończy zwraca 0, co wykorzystuje pętla while.

void przepisz(char * sciezka1, char * sciezka2) {
FILE * plik1=fopen(sciezka1,"rb");
FILE * plik2=fopen(sciezka2,"wb");
char c[100];
int n=100;
while(n==100){
   n=fread(c,1,100,plik1)'
   fwrite(c,1,n,plik2);
   }
fclose(plik1);
fclose(plik2);
}