16 CLA 7 Connecting to the real world: files and streams

PLIKI

Windows:  c:\directory\file   nie uwzględnia wielkość liter

Linux:      /directory/file            uwzględnia wielkość liter


i jeśli chcemy zapisać w stringu to w linuxie:   char *name="/dir/file:'
to w windows:                                                    char *name="c:\\dir\\file";


3 sposoby otwarcia strumienia:
read
write
update (read&write)


binarny vs tekstowy

tekstowy w liniach
binarny, sekwencja bajtów


W unix koniec linii to LF (ASCII kod 10) w C   \n
w windows CR  LF  (ASCII 13  10) w C   \r\n

polecenie dostępu do pliku:

FILE *fopen(char *filename, char *openmode);

jeśli sukces zwraca wskaźnik typu FILE, jeśli nie zwraca NULL
filename - nazwapliku
openmode - tryb odczytu

r  - read plik musi istniec i byc czytalny (nie istnieje błąd)
w - write, plik nie musi istniec  (jak istnieje kasuje, jak nie moze stworzyć błąd)
a  - append , jeśli istnieje dopisze na końcu
r+  - read and update, plik musi istniec, mozliwy odczyt i zapis
w+  - write and update,  plik nie musi istnieć, jeśli istnieje kasuje

dodanie literki b - np:  rb,  wb,  ab...tryb binarny
tryb tekstowy domyślny, ale mozna dopisać t np:  rt,   wt,   at

przykład:
FILE *file;

file = fopen("c:\\users\\user\\Desktop\\file.txt","rt");
if(file == NULL) {
    printf("File cannot be opened");
    return 1;
}

można skrócić do 1 linijki:

if((file = fopen("c:\\users\\user\\Desktop\\file.txt", "rt")) == NULL) {... }



3 OTWARTE STRUMIENIE

jeśli mamy dyrektywę
#include<stdio.h>

FILE  *stdin,  *stdout,   *stderr;


stdin - standard input, zwykle klawiatura (scanf czyta standardowo z tego strumienia)

stdout - standard output, zwykle ekran, standardowe wyjscie dla programow, printf wyrzuca na ekran

stderr - standard error output - standardowo ustawione na ekran,

można zmienić cel strumieni


FCLOSE

zamyka plik, wymaga tylko wskaźnika do pliku
zwraca 0 na sukces lub EOF  (-1) na błąd

int fclose(FILE *stream);


ERRNO

Error number

wymaga errno.h

extern int errno;

operacje na strumieniach które spowodują błąd zapiszą go do tej zmiennej

EACCES - brak dostępu
EBADF  - próba operacji na nie otwartym pliku

przykład:
FILE *file = fopen("c:\\file.txt","rt");
if(file == NULL) { 
    switch(errno) {
    case ENOENT: printf("The file doesn't exist\n"); 
                 break;
    case EMFILE: printf("You've opened too many files\n"); 
                 break;
    default:     printf("The error number is %d\n",errno);
    }
}


istnieje automatyczny sposób dotarcia do opisu błędu:
strerror (wymaga  string.h)

char *strerror (int errnum);

podajesz numer błędu i dostajesz wskaźnik do tekstu opisującego znaczenie błędu.


FUNKCJE CZYTAJĄCE ZE STRUMIENI

FGETC

fgetc - czyta jeden znak ze strumienia

int fgetc(FILE *stream);

fgetc(stdin);


przykład odczytywania znak po znaku pliku i wyswietlaniu tego na ekran:

#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE *inp; 
 int  chr;

 /* check if there is one argument */
 if(argc != 2) {
  printf("usage: show file_name\n");
  return 1;
 }

 /* check if we are able to open the input file */
 if((inp = fopen(argv[1],"rt")) == NULL) {
  printf("Cannot open the file %s\n", argv[1]);
  return 2;
 }

 /* we will try to read the file char by char and print the chars to screen */

 while((chr = fgetc(inp)) != EOF)
  printf("%c",chr);

 /* it's time to close the stream */
 fclose(inp);
 return 0;
}}


FGETS

czyta string ze streamu

char  *fgets(char  *str, int  maxsize,  FILE  *stream);

str - wskaźnik gdzie fgets będzie gromadził linie wziętą ze strumienia
maxsize  - maksymalna liczna znaków możliwa do przechowania w str
stream -  wskaźnik do strumienia (reading or update)

Funkcja czyta linie i zapisuje w buforze, jesli sukces zwraca wartość parametru str i przesuwa punkt czytania w nowe miejsce

NIE do czytania binarnych plików (czytanie ich linia po lini nie ma sensu) oraz gdy w binarnym bedzie \0 odczyta jako koniec wiersza

odmiana tej funkcji to
char* gets(char* str) która czyta ze strandardowego wejscia (stdin-klawiatura) ale nie sprawdza czy to pomieści się w str !!!

przykład odczytujący całe linie:
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE *inp;
 char line[128];
 if(argc != 2) {
  printf("usage: show2 file_name\n");
  return 1;
 }
 if((inp = fopen(argv[1],"rt")) == NULL) {
  printf("Cannot open the file %s\n", argv[1]);
  return 2;
 }
 while((fgets(line,sizeof(line),inp)) != NULL)
  printf("%s",line);
 fclose(inp);
 return 0;
}


FREAD
odczytuje bajty ze strumienia

int fread(voif  *mem, int size, int count, FILE *stream);

mem - wskaźnik do obszaru gdzie bedzie zapisywał bajty
size - rozmiar w bajtach jaki bedzie zapisywal
count - ilosc porcji zapisu
stream - co bedzie czytal

funkcja zwraca ilosc poprawnie odczytanych porcji, idealna do odczytu plików binarnych, można również czytać tekstowe, ale nie bez uwzględniania podziału na linie

przykład:
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE   *inp;
 unsigned char  buffer[1024]; /* 1 kilobyte */
 int   i, read;

 if(argc != 2) {
  printf("usage: show3 file_name\n");
  return 1;
 }
 if((inp = fopen(argv[1],"rb")) == NULL) {
  printf("Cannot open the file %s\n", argv[1]);
  return 2;
 }
 do {
  read = fread(buffer,1,sizeof(buffer),inp);
  for(i = 0; i < read; i++)
   printf("%02X",buffer[i]);
 } while (read > 0);
 fclose(inp);
 return 0;
}


FSCANF

jeśli w pliku mamy 3 kolejne znaku jako 128 i chcemy je odczytać jak jedną zmienna np typu INT
to tylko FSCANF pozwoli nam tego dokonać

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, albo innego typu (jesli float to 2 parametr "%f" )

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

przykład sortowania int wyciągniętych z plików tekstowych
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[]) {
 int  numbers[1000];
 int i,aux;
 int numbersread = 0;
 int swapped;
 FILE *inp;
 if(argc != 2) {
  printf("usage: intsort input_file\n");
  return 1;
 }
 if((inp = fopen(argv[1],"rt")) == NULL) {
  printf("Cannot open %s - %s\n",argv[1],strerror(errno));
  return 2;
 }
 while(fscanf(inp,"%d",&numbers[numbersread]) == 1) {
  numbersread++;
  if(numbersread == 1000)
   break;
}
 fclose(inp);
 if(numbersread == 0) {
  printf("No numbers found in the files %s\n",argv[1]);
  return 3;
 }
 do {
  swapped = 0;
  for(i = 0; i < numbersread - 1; i++)
   if(numbers[i] > numbers[i + 1]) {
    swapped = 1;
    aux = numbers[i];
    numbers[i] = numbers[i + 1];
    numbers[i + 1] = aux;
   }
 } while(swapped);
 printf("The sorted values: ");
 for(i = 0; i < numbersread; i++)
  printf("%d ",numbers[i]);
 printf("\n");
 return 0;
}


ZAPIS


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ład FPUTC
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE *inp, *out;
 int chr;

 /* check if we've got exactly two arguments */
 if(argc != 3) {
  printf("usage: copyc source_file target_file\n");
  return 1;
 }

 /* check if we are able to open the source file */
 if((inp = fopen(argv[1],"rb") )== NULL) {
  printf("Cannot open %s\n", argv[1]);
  return 2;
 }

 /* check if we are able to open the target file */
 if((out = fopen(argv[2],"wb")) == NULL) {
  printf("Cannot create %s\n", argv[2]);
  fclose(inp);
  return 3;
 }

 /* we are going to read char by char until we reach EOF */
 while((chr = fgetc(inp)) != EOF)
  if(fputc(chr, out) == EOF)
   break;
 fclose(inp);
 fclose(out);
 return 0;
}


Przykład FPUTS
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE    *inp, *out;
 char      line[128];

 if(argc != 3) {
  printf("usage: copys source_file target_file\n");
  return 1;
 }

 if((inp = fopen(argv[1],"rt")) == NULL) {
  printf("Cannot open %s\n", argv[1]);
  return 2;
 }
 if((out = fopen(argv[2],"wt")) == NULL) {
  printf("Cannot create %s\n", argv[2]);
  fclose(inp);
  return 3;
 }
 while((fgets(line,sizeof(line),inp)) != NULL)
  if(fputs(line,out) == EOF)
   break;
 fclose(inp);
 fclose(out);
 return 0;
}


Przykład  FWRITE
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
 FILE *inp, *out;
 char  buffer[16384]; /* 16 kilobytes */
 int read, written;

 if(argc != 3) {
  printf("usage: copyw source_file target_file\n");
  return 1;
 }
 if((inp = fopen(argv[1],"rb")) == NULL) {
  printf("Cannot open %s\n", argv[1]);
  return 2;
 }
 if((out = fopen(argv[2],"wb")) == NULL) {
  printf("Cannot create %s\n", argv[2]);
  fclose(inp);
  return 3;
 }
 do {
  read = fread(buffer,1,sizeof(buffer),inp);
  if(read)
   written = fwrite(buffer,1,read,out);
 } while (read && written);
 fclose(inp);
 fclose(out);
 return 0;
}


Przykład FPRINTF
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[]) {
 int  numbers[1000];
 int i,aux;
 int numbersread = 0;
 int swapped;
 FILE *inp, *out;
 if(argc != 3) {
  fprintf(stderr,"usage: intsort2 source_file target_file\n");
  return 1;
 }
 if((inp = fopen(argv[1],"rt")) == NULL) {
  fprintf(stderr,"Cannot open %s: %s\n",argv[1],strerror(errno));
  return 2;
 }
 if((out = fopen(argv[2],"wt")) == NULL) {
  fprintf(stderr,"Cannot create %s: %s\n",argv[2],strerror(errno));
  fclose(inp);
  return 3;
 }
 while(fscanf(inp,"%d",&numbers[numbersread]) == 1) {
  numbersread++;
  if(numbersread == 1000)
   break;
}
 fclose(inp);
 if(numbersread == 0) {
  printf("No numbers found in the file %s\n",argv[1]);
  return 3;
 }
 do {
  swapped = 0;
  for(i = 0; i < numbersread - 1; i++)
   if(numbers[i] > numbers[i + 1]) {
    swapped = 1;
    aux = numbers[i];
    numbers[i] = numbers[i + 1];
    numbers[i + 1] = aux;
  }
 } while(swapped);
 for(i = 0; i < numbersread; i++)
  fprintf(out,"%d\n",numbers[i]);
 printf("\n");
 fclose(out);
 return 0;
}



FTELL

pokazuje bieżącą pozycje w strumieniu

long  ftell(FILE *stream);

zwraca dystans w bajtach policzony od początku pliku
jeśli bła zwraca EOF (-1)
nie wpływa na pozycję


FSEEK

ustawia bieżącą pozycję

int fseek (FILE * stream, long offser, int whence);

offset - docelowa pozycja
whence - skąd liczona
   SEEK_SET - beginning
   SEK_CUR - current
   SEEK_END - end

jeśli błąd EOF(-1), oczywiściew wpływa na bieżącą pozycję

FILE *F;

fseek(F, 100, SEEK_SET);

fseek(F, -1, SEEK_CUR);



REWIND

z czasów taśm
nic nie zwraca, nie ustawia ERRNO

void rewind(FILE *stream)

równoznaczne z

fseek(stream, 0, SEEK_SET);    // czyli ustawia na początek



EOF i funkcja FEOF

end of file - pojawia się gdy nic do czytania

int feof(FILE *stream);

zwraca 0 gdy plik nie jest EOF albo zwraca coś innego jak JEST

więc można sprawdzić czy jest:


while(!feof (input))
{

fgets (line, sizeof(line), input));

fputs (line, output);

}


ZADANIA

Zad1
#include <stdio.h>
    int main(void) {
        FILE f;
        f = fopen("file","wb");
        printf("%d",f != NULL);
        fclose(f);
        return 0;
    }

Wynik  błąd kompilacji bo brak * w FILE f

Zad2

 #include <stdio.h>
    int main(void) {
        FILE *f;
        f = fopen("file","wb");
        printf("%d",f != NULL);
        fclose(f);
        return 0;
    }

Wynik 1, bo wszystko ok


Zad3

 #include <stdio.h>
    int main(void) {
        int i;
        i = fprintf(stdin,"Hello!");
        printf("%d",i == EOF);
        return 0;
    }

Wynik 0 , przeanalizować


Zad4

 #include <stdio.h>
    int main(void) {
        int i;
        i = fprintf(stderr,"Hello!");
        printf("%d",i == EOF);
        return 0;
    }

Wynik 0, ale dodatkowo na wyjsciu blędów, czyli ekranie wyswietli hello, wiec bedzie Hello!0

Zad5

 #include <stdio.h>
    int main(void) {
        FILE *f;
        int i = fprintf(f,"Hello!");
        printf("%d",i == EOF);
        return 0;
    }

Wynik błąd wykonania, bo nie ma otwarcia pliku

Zad6

   #include <stdio.h>
    int main(void) {
        FILE *f = fopen("file","w");
        int i = fprintf(f,"Hello!");
        printf("%d",i != EOF);
        return 0;
    }

Wynik 1 bo OK

Zad7

  #include <stdio.h>
    int main(void) {
        FILE *f = fopen("file","w");
        int i = fputs(f,"Hello!");
        printf("%d",i != EOF);
        fclose(f);
        return 0;
    }

Wynik błąd, bo fputs...przeanalizować !!

Zad8

  #include <stdio.h>
    int main(void) {
        FILE *f = fopen("file","w");
        int i = fputs("Hello!",f);
        printf("%d",i != EOF);
        return 0;
    }
Wynik 1, fputs poprawnie :-)

Zad9

    #include <stdio.h> 
    int main(void) { 
        char s[20]; 
        FILE *f = fopen("file","w"); 
        int i = fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fgets(s,2,f); 
        puts(s); 
        fclose(f); 
        return 0; 
    }

Wynik 1 , przeanalizować czemu nie 2 znaki

Zad10
   #include <stdio.h> 
    int main(void) { 
        char s[20]; 
        FILE *f = fopen("file","w"); 
        int i = fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fgets(s,20,f); 
        puts(s); 
        fclose(f); 
        return 0; 
    }

Wynik 12A 

Zad11

    #include <stdio.h> 
    int main(void) { 
        FILE *f = fopen("file","w"); 
        int i; 
        fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fseek(f,0,SEEK_END); 
        i = ftell(f); 
        fclose(f); 
        printf("%d",i); 
        return 0; 
    }

Wynik: 3, bo jest na koncu a mamy 3 znaki

Zad12

    #include <stdio.h> 
    int main(void) { 
        FILE *f = fopen("file","w"); 
        int i; 
        fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fseek(f); 
        i = ftell(f,0,SEEK_END); 
        fclose(f); 
        printf("%d",i); 
        return 0; 
    } 

Wynik błąd, bo fseek potrzebuje wiecej argumentow

Zad13

    #include <stdio.h> 
    int main(void) { 
        FILE *f = fopen("file","w"); 
        int i; 
        fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fscanf(f,"%d",&i); 
        fclose(f); 
        printf("%d",i); 
        return 0; 
    }

Wynik 12, bo odczytuje liczbę int za pomocą fscanf

Zad 14

    #include <stdio.h> 
    int main(void) { 
        FILE *f = fopen("file","w"); 
        char c; 
        fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fscanf(f,"%c",&c); 
        fclose(f); 
        printf("%c",c); 
        return 0; 
    }

wynik 1, zmyłka, bo nie A jest pierwszym char, ale 1 też nim jest!

Zad15
    #include <stdio.h> 
    int main(void) { 
        FILE *f = fopen("file","w"); 
        float f; 
        fputs("12A",f); 
        fclose(f); 
        f = fopen("file","r"); 
        fscanf(f,"%f",&f); 
        fclose(f); 
        printf("%f",f); 
        return 0; 
    }

Wynik błąd, ale zmyłka bo float f pokrywa się z FILE *f, gdyby float był inny wynik 12.0000