Laboratorium Podstaw Informatyki Strona 1 Laboratorium Podstaw Informatyki Kierunek Elektrotechnika Ćwiczenie 4 Obsługa plików Kraków 2010
Laboratorium Podstaw Informatyki Strona 2 Obsługa plików Zanim będziemy mogli czytać lub pisać z/do pliku, musi być on otwarty przy pomocą funkcji fopen. Wywołanie funkcji fopen w programie ma postać: fp = fopen(name, mode); Pierwszym argumentem fopen jest nazwa pliku w postaci tekstowej. Drugi argument, również tekstowy, informuje o trybie dostępu do pliku. Dopuszcza się następujące tryby: czytanie "r", pisanie "w", i dopisywanie "a". Dodatkowo można dołączyć literkę "b", która zapewni, że plik zostanie otwarty w trybie binarnym. Tryb ten używany jest do otwierania plików zawierających dane binarne tj np. obrazy (*.bmp, *.jpg), dźwięki (*.wav, *.mp3), pliki wykonywalne (*.exe). Funkcja fopen zwraca wskaźnik do pliku (ściśle do struktury opisującej otwarty plik), który przypisujemy do zmiennej fp. Oczywiście fp powinien być wcześniej zadeklarowany jako: Deklaracja ta mówi, że fp jest wskaźnikiem do obiektu typu FILE. Wywołanie funkcji fopen może się zakończyć błędem, wtedy funkcja zwraca wartość NULL. Gdy plik jest już otwarty można z niego czytać lub pisać. Najprostszymi funkcjami przeznaczonymi do tego są fgetc i fputc. Funkcja fgetc zwraca kolejny znak wczytany z pliku np. c = fgetc(fp); Gdy nie ma już więcej znaków funkcja kończy działanie i zwraca wartość EOF. Wartość EOF jest stałą zdefiniowaną w pliku nagłówkowym. Jej wartością zazwyczaj jest -1, stąd typem wartości zwracanym przez funkcję fgetc musi być int. Z tego powodu zmienna c również powinna być typu int. Funkcja fputc działa przeciwnie, tzn. wstawia znak c do pliku fp: fputc(c, fp); Przykład: Zadaniem programu jest wyświetlenie zawartości tekstowego pliku "plik.txt" na ekran. Uwaga: plik należy wcześniej utworzyć korzystając z edytora ASCII (np. notatnik). #include <stdio.h> main( ) { fp = fopen("c:\\plik.txt", "r"); if(fp == NULL) { printf("nie udalo się otworzyc pliku: c:\\plik.txt \n"); return -1; while((c=fgetc(fp))!=eof) putc(c, stdout); fclose(fp); return 0; stdout jest predefiniowanym strumieniem wyjściowym otwieranym automatycznie po uruchomieniu programu. Innym tym razem wejściowym (klawiatura) predefiniowanym strumieniem jest stdin.
Laboratorium Podstaw Informatyki Strona 3 Zadanie 1: Napisz program kopiuj, który skopiuje zadany plik wejściowy na plik wyjściowy używając omówionych powyżej funkcji. Zadanie 2: Napisz program, który dla podanego pliku tekstowego (np. poprzedniego "plik.txt") policzy histogram, czyli częstość wystąpienie poszczególnych literek w nim. Uwaga warto skorzystać z wyników zadania z poprzednich zajęć. Często czytanie po jednym znaku jest nie wygodne. Dlatego do czytania i pisania większych porcji danych z/do pliku służą odpowiednio funkcje fread i fwrite. Deklaracja funkcji fread zamieszczona w zbiorze nagłówkowym stdio.h ma postać: size_t fread(void *ptr, size_t size, size_t n, FILE *stream); Oznacza ona, że funkcja fread czyta, z pliku określonego przez stream (to samo co fp poprzednio, ale inna nazwa - popatrz na typ), podaną ilość elementów (n) o jednakowej wielkości (size). Funkcja zwraca ilość faktycznie przeczytanych elementów - nie bajtów. Znaczenie argumentów jest następujące: void *ptr wskaźnik na blok pamięci do którego zostaną zapisane przeczytane dane size_t size rozmiar pojedynczego elementu size_t n ilość elementów do przeczytania FILE *stream wskaźnik do pliku z którego będziemy czytać Deklaracja funkcji fwrite zamieszczona w zbiorze nagłówkowym stdio.h ma postać size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream); Funkcja fwrite zapisuje, do pliku określonego przez stream, podaną ilość elementów (n) o jednakowej wielkości (size). Funkcja zwraca ilość zapisanych elementów. Znaczenie argumentów jest następujące: const void *ptr wskaźnik na blok pamięci zawierający dane, które mają być zapisane do pliku przez funkcję fwrite. Słówko const oznacza, że funkcja nie zmienia podczas swojego działania zawartości przekazanego jej bufora. size_t size rozmiar pojedynczego elementu, które będą zapisywane size_t n ilość elementów do zapisania FILE *stream wskaźnik do pliku, do którego będziemy zapisywać Przykład: Zadaniem programu jest przeczytanie z podanego pliku dziesięciu bajtów i wyświetlenie ich na ekran w kodzie hex i w postaci znaków. #include <stdio.h> main( ) { int i, j;
Laboratorium Podstaw Informatyki Strona 4 char buf[10]; fp = fopen("c:\\plik.txt", "r"); if(fp == NULL) { printf("nie udalo się otworzyc pliku: c:\\plik.txt \n"); return -1; i = fread(buf, 1, 10, fp); j=0; while(i--) { printf("znak %c ma kod %X (hex)\n", buf[j], buf[j]); j++; fclose(fp); return 0; Zadanie 3: Napisać program kopiuj, który skopiuje plik wejściowy na plik wyjściowy. Do rozwiązania zadania użyć funkcji fwrite i fread, które będą pisać/czytać większymi, ustalonymi wcześniej porcjami (np. po 10 bajtów). Zauważ, że długość kopiowanego pliku nie musi być (i na ogół nie jest) całkowitą wielokrotnością przyjętej porcji czytania. Zastanów się jak rozwiązać ten problem. Popularna funkcja printf ma swój odpowiednik fprintf, który wyprowadza wynik działania nie na ekran lecz do pliku. Przykładowe użycie wyjaśnia zarazem sposób przekazywania parametrów: fprintf(fp, "znak %c ma kod %X (hex)\n", X, X ); oczywiście FILE *fp jest wskaźnikiem do otwartego wcześniej pliku. Zadanie 4(a): Napisz funkcję hist(char *tekst, int *htab_sl, int *htab_d), która wyznaczy histogramy (liczbę wystąpień) wszystkich małych literek i umieści te informacje w tablicy htab_sl i cyfr w htab_d w podanym tekście. Funkcja jako pierwszy parametr dostaje wskaźnik do tekstu, który ma być analizowany, a jako drugi i trzeci wskaźnik do tablicy, gdzie mają być umieszczone histogramy. Program, który będzie wywoływał funkcję hist ma następnie wypisać otrzymane histogramy w formie tabelki. Przykładowo: int hl[ z - a +1], hd[10]; /*deklaracja potrzebnych tablic*/ hist("aacdd", hl, hd); /*wywołanie funkcji*/ po zakończeniu funkcji tablica hl, będzie zawierać następujące pozycje niezerowe hl[0]=2, hl[2]=1, hl[3]=2; bo w podanym tekście wystąpiły dwie litery a, jedna c i dwie d. Zadanie 4(b): Zmodyfikować zadanie 4(a) tak, aby histogram był wyprowadzany równocześnie do podanego pliku jak i na ekran. W tym celu należy napisać funkcję DrukujHist(int *hist, FILE *fp), w której ciele należy użyć funkcji fprintf. Funkcja DrukujHist będzie w programie wołana 2 raz: raz z parametrem fp wskazującym na plik dyskowy, a drugi raz równym stdout, aby wyświetlić wynik na ekranie.
Laboratorium Podstaw Informatyki Strona 5 Zadanie 5: Rozszerzyć napisany program z zadania 3, tak aby mógł być użyty do konkatenacji (t.j. sklejania) kilku plików. Nazwy plików do sklejenia będą zadawane w tablicy tekstów, np. char *fn[] = { plik1, plik2, wynik, NULL;. Przy tak zadeklarowanej tablicy fn[0] jest tekstem (tj. numerem komórki pamięci w której umieszczony jest pierwszy znak tekstu) plik1, fn[2] wskazuje na wynik, a fn[3] jest NULL. Widać więc jaki powinien być warunek na zakończenie pętli przeglądającej taką tablicę. Przy takiej zawartości tablicy do pliku wynik najpierw zostanie wpisana zawartość pliku plik1, a potem dopisana zawartość pliku plik2.