Formatowane pisanie i czytanie
Formatowane czytanie i pisanie do plików w C jest dość dokładnie opisane tutaj. Znacznie dokładniejsze informacje można jednak znaleźć tutaj. Kod najprostszego programu C realizującego formatowane pisanie do pliku jest przedstawiony poniżej:
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. int main ()
5. {
6. FILE *fp;
7. int liczba;
8. fp=fopen("test.txt","r");
9. if (fp==NULL) {
10. printf ("Nie mogę otworzyć pliku test.txt do czytania!\n");
11. exit(1);
12. }
13. fscanf(fp, "%d", &liczba);
14. fclose (fp);
15. return 0;
16. }
Aby wykonywać wysokopoziomowe operacje na plikach w programach pisanych w C należy zadeklarować użycie zmiennej przechowującej tzw. uchwyt do pliku. Ta deklaracja jest umieszczona w 6 linii kodu. Plik jest otwierany po wywołaniu funkcji fopen() (linia 8) i od tego momentu zmienna fp wskazuje na plik test.txt, przekazany jako argument do funkcji fopen(). Drugi argument funkcji fopen() ("r") oznacza, że plik jest otwierany do odczytu (próba pisania do pliku otwartego w takim trybie zakończy się błędem).
Jeżeli plik test.txt nie istnieje, to funkcja fopen() zwróci wartość NULL - czytanie z nieistniejącego pliku z reguły nie ma sensu, w takim wypadku instrukcja warunkowa (linia 9) dokona bezpiecznego zamknięcia programu.
Czytanie z pliku realizuje się funkcją fscanf() (linia 13), która działa analogicznie do funkcji scanf() - wyjątkiem jest dodatkowy, pierwszy argument funkcji fscanf(), którym musi być uchwyt do pliku z którego czytamy.
Po przeczytaniu z pliku wszystkich interesujących nas danych plik zamykamy, korzystając z funkcji fclose().
Jeżeli zamierzamy czytać z pliku np. 10 liczb, wywołamy oczywiście funkcję fscanf() 10 razy, korzystając z odpowiedniej pętli. Warto pamiętać o tym, że funkcja fscanf() po napotkaniu końca pliku zwraca wartość EOF. Bezpieczne czytanie liczb z pliku o nieznanej długości można zrealizować przedstawionym poniżej kodem:
1. int liczba;
2. fp=fopen("test.txt","r");
3. while(fscanf(fp,"%d",&liczba)!=EOF)
4. {
5. //wykonaj jakieś instrukcje
6. }
7. fclose(fp);
Formatowane pisanie do pliku jest możliwe po wcześniejszym otwarciu pliku w trybie do pisania (drugi argument funkcji fopen() równy "w"), lub dopisywania (drugi argument funkcji fopen() równy "a"). Jeśli plik, do którego chcemy pisać nie istnieje, zostanie utworzony. Formatowane pisanie do pliku realizujemy przy użyciu funkcji fprintf(), działającej analogicznie do funkcji printf() - podobnie jak w przypadku funkcji fscanf(), dodatkowym, pierwszym argumentem funkcji fprintf() musi być uchwyt do pliku do którego piszemy. Prosty kod programu piszącego do pliku test.txt jest przedstawiony poniżej.
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. int main ()
5. {
6. FILE *fp;
7. char tekst[]="To jest bardzo ważna informacja";
8. fp=fopen("test.txt","w");
9. fprintf(fp, "%s", tekst);
10. fclose (fp);
11. return 0;
12. }
To jest bardzo ważna informacja: Opisane powyżej funkcje fprintf() i fscanf() nadają się tylko do obsługi plików tekstowych. Obsługa plików binarnych (np. bitmapy) realizowana jest przy użyciu innego zestawu funkcji do czytania i pisania.
Treść pliku rozliczenie.txt składa się zawsze z nieznanej ilości wierszy. Każdy wiersz zawiera nazwę towaru (jedno słowo, bez białych znaków) oraz cenę np:
kanapka 2.50
szarlotka 1.50
woda_mineralna 1.50
Napisać program obliczający całkowitą należność do zapłaty i dopisującą tą należność do pliku rachunki.txt.
Wskazówka:
Do czytania można użyć funkcji fscanf(), ponieważ sekwencja danych wejściowych w pliku jest ustalona i dość prosta
Treść pliku rozliczenie.txt składa się zawsze z nieznanej ilości wierszy. Tym razem jednak każdy wiersz zawiera nazwę towaru, która może zawierać białe znaki (np. spacje) oraz cenę, oddzieloną dwukropkiem od nazwy np:
kanapka: 2.50
szarlotka: 1.50
woda mineralna: 1.50
Napisać program obliczający całkowitą należność do zapłaty i dopisującą tą należność do pliku rachunki.txt.
Wskazówki:
ponieważ sekwencja danych wejściowych w pliku rozliczenie.txt nie jest ustalona, nie można więc użyć do czytania funkcji fscanf() - odpowiednią funkcją czytającą będzie w tym wypadku fgets(), czytająca całą linię z pliku do zmiennej napisowej (wcześniej zadeklarowanej),
linię pliku rozliczenie.txt, wczytaną funkcją fgets() należy przeszukać, w celu wykrycia miejsca wystąpienie dwukropka - zadanie to można wykonać albo bezpośrednio operując na tablicy napisowej, albo wykorzystując funkcję strchr(),
zawartość linii tekstu od miejsca wystąpienia dwukropka do końca napisu należy przekopiować do nowej zmiennej napisowej (np. znak po znaku w pętli do ostatniego znaku linii, długość linii tekstu jest zwracana przez funkcję strlen()), a następnie użyć funkcji atof() w celu wydobycia liczby.
Proszę napisać program, który czyta słowa z pliku o nazwie zapisanej w pliku input.txt, oblicza średnią, minimalną i maksymalną długość słów oraz ilość słów, a wyniki umieszcza w pliku statystyka.dat.
Wskazówki:
po otwarciu pliku input.txt należy z niego przeczytać słowo zawierające nazwę pliku do otwarcia - nazwa ta trafia do wcześniej zadeklarowanej zmiennej napisowej,
zmienną napisową o tak nadanej wartości należy przekazać jako argument do funkcji fopen(),
ponieważ czytamy plik słowo po słowie, do czytania można użyć funkcji fscanf(),
do wyznaczenia długości słowa jak zwykle wykorzystamy funkcję strlen().
Proszę napisać program, który czyta plik o nazwie zapisanej w pliku input.txt i zlicza w pliku ilość linii, słów i znaków. Wyniki mają trafić do pliku statystyka.dat.
Wskazówki:
linie czytamy funkcję fgets(), zwracającą wartość NULL po napotkaniu końca pliku,
słowa czytamy funkcją fscanf(), zwracającą wartość EOF po napotkaniu końca pliku,
znaki czytamy funkcją fgetc(), zwracającą wartość EOF po napotkaniu końca pliku,
pliki przeczytane do końca można przewinąć do początku funkcją rewind().
Argumenty linii poleceń
Działanie programów z Zadań 1-4 byłoby znacznie bardziej elastyczne, gdyby nazwy plików przeznaczonych do czytania były zadawane dynamicznie, a nie statycznie wprowadzone do kodu programu. Efekt taki można bardzo prosto uzyskać stosując obsługę argumentów linii poleceń. Użycie argumentówlinii poleceń jest zaprezentowane w poniższym kodzie.
1. #include <stdio.h>
2.
3. int main(int argc, char *argv[])
4. {
5. int i;
6. for(i=0;i<argc;i++)
7. printf("%s\n",argv[i]);
8. }
W odróżnieniu od kodów przedstawionych dotychczas, funkcja main() posiada dwa argumenty (linia 3). Argument argc (typu całkowitego) przechowuje liczbę słów wpisanych w linii poleceń, uwzględniając nazwę programu. Tablica napisowa argv[], przechowuje słowa wpisane w linii poleceń: argv[0] jest nazwą programu, argv[1] jest pierwszym argumentem wywołanego programu (tylko gdy w linii poleceń wpiszemy coś więcej niż tylko nazwę programu) itd...
Program, którego kod zapisano powyżej można wywołać z linii komend systemu operacyjnego, dodając po nazwie programu dowolne słowa (Rys. 1), które mogą zostać w programie wykorzystane do konkretnych celów.
Rys. 1 Program wywołany z argumentami linii poleceń
Proszę przepisać programy z Zadań 1-4, tak aby pisanie i czytanie odbywało się z/do plików o nazwach pobranych z linii poleceń. Jeżeli w linii poleceń nie zostanie podana nazwa pliku do czytania lub pisania, program ma informować użytkownika, że pisanie/czytanie będzie wykonane na pliku o standardowej (zadanej w kodzie programu) nazwie.
Wskazówka:
Jeżeli zmienna argc jest mniejsza od 2 to w linii poleceń nie podano żadnego argumentu
Proszę napisać program tail, który wypisuje ostatnich N linii pliku o zadanej nazwie. Zarówno nazwa pliku do czytania, jak i liczba ostatnich linii do wypisania mają być pobrane z linii poleceń.
Proszę napisać program more, który wypisuje po N linii pliku o zadanej nazwie. Zarówno nazwa pliku do czytania, jak i liczba linii do wypisania mają być pobrane z linii poleceń. Po wypisaniu N linii program oczekuje na naciśnięcie dowolnego klawisza i po naciśnięciu klawisza wypisywanych jest N kolejnych linii pliku, aż do napotkania końca pliku. Jeżeli użytkownik naciśnie klawisz 'q' lub ESC, program ma zakończyć działanie.
Wskazówki:
do przerwania działania programu można wykorzystać funkcję getch()
wartość zwracaną przez funkcję getch() (np. 97 po naciśnięciu klawisza 'a') można wykorzystać do obsłużenia wyjścia z programu