Wykład VI Wydział Matematyki Stosowanej Politechniki Śląskiej Gliwice, 2014 c Copyright 2014 Janusz Słupik
Operacje na plikach
Operacje na plikach Aby móc korzystać z pliku należy go otworzyć w odpowiednim trybie. Opcje: b - tryb binarny w - tryb zapisu r - tryb czytania a - tryb dopisywania FILE *plik; plik = fopen( "nazwa.txt", "r" ); if( plik == NULL ) printf( "Nieudane otwarcie" ); else... fclose( plik );
Funkcje zapisu FILE *plik; int x = 5; char nazwa[] = "dane.txt"; plik = fopen( nazwa, "w" ); fputc( A, plik ) ; fputs( "napis", plik ); fprintf( plik, "x= %d", x );
Funkcje odczytu FILE *plik; char linia[100]; int z; plik = fopen( "dane.txt", "r" ); z = fgetc( plik ); fgets( linia, 100, plik ); fscanf( plik, "%d", &z );
Przykład - kopia pliku bajt po bajcie FILE *wej, *wyj; int z; wej = fopen( "jeden.cos", "rb" ); if( wej == NULL ) printf("\nnieudane otwarcie pliku do kopiowania\n"); else wyj = fopen( "kopia.cos", "wb" ); while(1) z = fgetc( wej ); if( z == EOF ) break; fputc( z, wyj ); fclose( wej ); fclose( wyj );
Pozycjonowanie w pliku int poz; poz = ftell( plik ); //aktualna pozycja fseek( plik, 5, SEEK_CUR ); //przesuń o 5 bajtów SEEK CUR - względem aktualnej pozycji w pliku SEEK SET - względem początku pliku SEEK END - względem końca pliku fseek( plik, 0, SEEK_END); //przesuń na koniec fseek( plik, 0, SEEK_END); liczba = ftell( plik ); rewind( plik ); //liczba bajtów w pliku //"przewiń" do początku
Zapis/odczyt bloku pamięci Wczytanie pod wskazany adres podanej liczby elementów określonego rozmiaru z pliku. Zwraca liczbę poprawnie wczytanych elementów. fread( wskaźnik, rozmiar_elementu, liczba, plik ); Zapisanie spod wskazanego adresu podanej liczby elementów określonego rozmiaru do pliku. Zwraca liczbę zapisanych elementów jeśli zapis był poprawny. fwrite( wskaźnik, rozmiar_elementu, liczba, plik );
Przykład - tablica w pliku Zapis: FILE *wyj; int t[10] = 1,2,3,4,5,6,7,8,9,10; wyj = fopen( "tab.dat", "wb" ); fwrite( (void *) t, sizeof(int), 10, wyj ); fclose(wyj); Odczyt: int u[10]; wej = fopen( "tab.dat", "rb" ); fread( (void *) u, sizeof(int), 10, wej ); fclose(wej);
Przykład - ładowanie całego pliku do pamięci main() char *p = NULL; int n = 0; n = wczytajplik( "main.c", &p ); if( n ) // Przykładowe użycie: // Wypisanie na ekranie zawartości pliku od końca while( --n >= 0 ) printf("%c", p[n] ); free( p ); system("pause"); return 0;
Przykład c.d. - ładowanie całego pliku do pamięci int wczytajplik( char *nazwapliku, char **gdzie ) FILE *plik; int rozmiar = 0, z = 0, i = 0; plik = fopen( nazwapliku, "rb" ); if( plik == NULL ) return 0; fseek( plik, 0, SEEK_END ); rozmiar = ftell( plik ); fseek( plik, 0, SEEK_SET ); *gdzie = malloc( rozmiar ); if( *gdzie == NULL ) return 0; while(1) if( ( z = fgetc(plik) ) == EOF ) break; *( *gdzie + i ) = z; i++; fclose( plik ); return rozmiar;
Przykład 2. Prosta kompresja danych.
Idea kompresji - zmodyfikowana metoda ByteRun Plik źródłowy: a a a b b b b b c d a c b b b Sekwencje powtarzających się symboli kodujemy: ilość znak gdzie ilość to bajt zawierający liczbę: 2... 127 Sekwencje różnych symboli kodujemy: -ilość z1 z2... zn gdzie -ilość to bajt zawierający liczbę: -128... -1 Po zakodowaniu: 3 a 5 b -4 c d a c 3 b
Plik BMP Plik BMP składa się z nagłówków oraz danych opisujących poszczególne piksele. W 24 bitowej bitmapie każdemu pikselowi przypisane są 3 bajty. Każdy wiersz tablicy pikseli jest wyrównany do wielokrotności 4 bajtów. nagłówki piksel piksel... b1 b2... bn r1 g1 b1 r2 g2 b2...
Przykład - Prosty kompresor plików BMP Założenia: - plik poddawany kompresji jest w formacie BMP, - obraz nie jest fotografią, lecz grafiką: diagramem, banerem, komiksem, itp. - kompresowanie: program.exe -k plik.bmp nowy.bin - dekompresowanie: program.exe -d nowy.bin plik.bmp Idea kompresji: - zastosujemy zmodyfikowaną metodę ByteRun; - będziemy badali sekwencje pojedynczych bajtów. Dla obrazów w postaci 24 bitowej można polepszyć stopień kompresji badając nie pojedyncze bajty lecz ich trójki, aby wykryć powtarzające się piksele. Jednakże ze względu na stopień złożoności kodu nie będziemy tego implementować w ten sposób.
main( int argc, char *argv[] ) char *p = NULL; int n; if( argc > 3 ) n = wczytajplik( argv[2], &p ); if( n ) if( strcmp( argv[1], "-k" ) == 0 ) kompresuj( argv[3], p, n ); else dekompresuj( argv[3], p, n ); free( p ); system("pause"); return 0;
Przed funkcją main: #include <stdio.h> #include <stdlib.h> int wczytajplik( char *, char ** ); void kompresuj( char *, char *, int ); void dekompresuj( char *, char *, int ); void zapiszpowtorzenia( FILE *, int, char ); void zapiszrozneznaki( FILE *, int, char * ); //...
void dekompresuj( char *nazwapliku, char *t, int n ) int pozycjaodczytu = 0, krotnosc = 0; FILE *plik = NULL; plik = fopen( nazwapliku, "wb" ); while( pozycjaodczytu < n ) krotnosc = t[ pozycjaodczytu++ ]; if( krotnosc < 0 ) krotnosc *= (-1); while( krotnosc-- ) fputc( t[ pozycjaodczytu++ ], plik ); else while( krotnosc-- ) fputc( t[ pozycjaodczytu ], plik ); pozycjaodczytu++; fclose( plik );
void zapiszpowtorzenia( FILE *plik, int ile, char znak ) while( 1 ) if( ile > 127 ) fputc( 127, plik ); ile -= 127; fputc( znak, plik ); else fputc( ile, plik ); fputc( znak, plik ); break;
void zapiszrozneznaki( FILE *plik, int ile, char *t ) int i; while( 1 ) if( ile > 128 ) fputc( -128, plik ); for( i=0; i<128; i++ ) fputc( *t++, plik ); ile -= 128; else fputc( ile*(-1), plik ); while( ile-- > 0 ) fputc( *t++, plik ); break;
void kompresuj( char *nazwapliku, char *t, int n ) char znak = t[0]; int pozycjaodczytu = 1; int iloscpowtorzen = 0, iloscroznic = 0; FILE *plik = fopen( nazwapliku, "wb" ); while( pozycjaodczytu < n ) while( pozycjaodczytu < n ) // szukamy kolejnych powtorzeń if( znak == t[ pozycjaodczytu ] ) iloscpowtorzen++; pozycjaodczytu++; else break; if( iloscpowtorzen > 0 ) zapiszpowtorzenia( plik, ++iloscpowtorzen, znak ); iloscpowtorzen = 0; if( pozycjaodczytu+1 < n ) znak = t[ pozycjaodczytu++ ]; //...
//... // szukamy ile jest kolejnych różnych znaków while( pozycjaodczytu+iloscroznic < n ) if( znak!= t[ pozycjaodczytu + iloscroznic ] ) znak = t[ pozycjaodczytu + iloscroznic++ ]; else break; if( iloscroznic > 0 ) if( pozycjaodczytu + iloscroznic == n ) iloscroznic++; zapiszrozneznaki( plik, iloscroznic, t+pozycjaodczytu-1); pozycjaodczytu += iloscroznic; iloscroznic = 0; fclose( plik );
Przykładowe dane: plik pogoda.bmp o rozmiarze 1 128 654 bajtów Po kompresji ma 656 825 bajtów.
Solucja w VS2008 zawierająca pełny kod tego programu znajduje się pod adresem: http://157.158.16.139/js/wyklady/solucje/kompresorbmp.zip
Koniec