Пример 8

/* Пример маленькой базы данных. * Данные хранятся БЕЗ дубликатов. * Надо заметить, что используется плохой (неэффективный) * алгоритм доступа - линейный поиск. */ #include <stdio.h> /* Все записи в базе имеют фиксированный размер */ #define VLEN 20 #define KEY_FREE (-13) /* ключ свободного места. Он выбран произвольно, но не должен встречаться в качестве входных данных */ struct data{ short b_key; /* ключ */ char b_val[VLEN]; /* строка-значение */ }; char BASEF[] = ".base" ; /* имя файла базы */ FILE *fbase; /* pointer на базу */ struct data tmp; /* вспомогательная переменная */ void initBase (void){ /* fopen: r read (чтение) * w write (запись), файл пересоздается. * (создается, если не было, если был - опустошается). * r+ чтение и запись (файл уже существует). * w+ чтение и запись (создается пустой файл). * a append (запись в конец файла), создать если нет: * имеется в виду, что КАЖДАЯ операция записи сначала * ставит указатель записи на конец файла. * В MS DOS нетекстовый файл НЕОБХОДИМО открывать как * rb wb rb+ wb+ ab+ иначе ничего не будет работать. */ if(( fbase = fopen( BASEF, "r+" )) == NULL ){ if(( fbase = fopen( BASEF, "w+" )) == NULL ){ fprintf( stderr, "Не могу открыть базу данных %s\n", BASEF ); exit(1); } fprintf( stderr, "База создана\n" ); } } void closeBase (void){ fclose( fbase ); } /* Учтите, что если вы записываете в файл структуры, то в файле не будет разделения на строки - файл НЕТЕКСТОВЫЙ! Поэтому и читать такой файл можно только структурами: read(), fread() (но не scanf-ом и не fgets-ом) */ /* Поиск по ключу . Выдать (-1), если записи с данным ключом нет, иначе - номер слота, где содержится запись с данным ключом. */ int bget (int key) { int n; /* последовательно просмотреть весь файл */ rewind( fbase ); /* в начало файла. Равно fseek(fbase, 0L, 0); */ n = 0 ; /* int сколько_элементов_массива_действительно_считано = * fread( адрес_массива_куда_считывать, * размер_одного_элемента_массива, * сколько_элементов_считывать_в_массив, канал ); * Заметьте, что количество данных задается НЕ в байтах, * а в 'штуках' */ while( fread( &tmp, sizeof( tmp ), 1, fbase ) == 1 ){ if( tmp.b_key == key ) return n; n++; } return (-1); /* не найдено */ } /* модифицировать запись с индексом ind */ void bmod ( int ind, int key, /* новый ключ */ char *val /* новое значение */ ) { struct data new; fseek( fbase, (long) sizeof( struct data ) * ind, 0 ); new.b_key = key; strncpy( new.b_val, val, VLEN ); /* int сколько_элементов_массива_действительно_записано = * fwrite( адрес_массива_который_записывать, * размер_одного_элемента_массива, * сколько_элементов_массива_записывать, канал ); */ if( fwrite( &new, sizeof new , 1, fbase ) != 1 ) fprintf( stderr, "Ошибка записи.\n" ); } /* удаление записи по ключу */ int bdel (int key){ int ind = bget( key ); if( ind == -1 ) return (-1); /* записи с таким ключом нет */ bmod( ind, KEY_FREE, "" ); /* записать признак свободного места */ return 0; } /* Служебная процедура дописи к концу файла */ void bappend (int key, char *val) { struct data new; /* встать на конец файла */ fseek( fbase, 0L, 2 ); /* и записать новую структуру в конец */ new.b_key = key; strncpy( new.b_val, val, VLEN ); fwrite( &new, sizeof( struct data ) , 1, fbase ); } /* добавление новой записи. Если запись с таким ключом уже есть выдать ошибку */ int bput (int key, char *val) { int i = bget( key ); if( i != -1 ) return (-1); /* запись уже есть */ /* найти свободное место */ i = bget( KEY_FREE ); if( i == -1 ) { /* нет свободных мест */ bappend( key, val ); return 0; } /* иначе свободное место найдено. * Заменяем дырку на полезную информацию */ bmod( i, key, val ); } /* распечатать всю базу данных подряд */ void bprint (void){ int n; int here = 0; rewind( fbase ); n = 0; printf( "-номер--ключ-------значение-----------------\n" ); while( fread( &tmp, sizeof tmp, 1, fbase ) == 1 ){ if( tmp.b_key == KEY_FREE ){ n++; continue; } printf( "#%-2d| %6d\t| %s\n", n, tmp.b_key, tmp.b_val ); here ++; n++; } printf( "--------------------------------------------\n" ); printf( "Длина базы:%d Занято:%d\n\n", n, here ); } /* замена поля val у записи с ключом key */ int bchange (int key, char *val) { int ind; ind = bget( key ); if( ind == -1 ){ /* запись с таким ключом не существует */ /* Добавить как новую запись */ bput( key, val ); return 0; } bmod( ind, key, val ); return 1; } /* Аналогичная функция, но использующая другой способ. * Кроме того, если такой ключ отсутствует - ничего не делается */ int bchg (int key, char *val) { struct data d; rewind( fbase ); /* в начало файла */ while( fread( &d, sizeof d, 1, fbase ) == 1 ){ /* поиск ключа */ if( d.b_key == key ){ /* вернуться назад от текущей позиции */ fseek( fbase, - (long) sizeof d, 1 ); /* не годится (long)-sizeof d !!! */ d.b_key = key; strncpy( d.b_val, val, VLEN ); fwrite( &d, sizeof d, 1, fbase ); /* между fread и fwrite должен быть * хоть один fseek. (магическое заклинание!) */ fseek( fbase, 0L, 1); /* никуда не сдвигаться */ return 0; /* сделано */ } } return (-1); /* такого ключа не было */ } /* Пример */ void main (void){ int i; initBase(); bprint(); bdel( 8 ); printf( "Создаем базу данных\n" ); bput( 1, "строка 1" ); bput( 2, "строка 2" ); bput( 3, "строка 3" ); bput( 4, "строка 4" ); bprint(); printf( "Удаляем записи с ключами 1 и 3\n" ); bdel( 1 ); bdel( 3 ); bprint(); printf( "Добавляем записи 5, 6 и 7\n" ); bput( 5, "строка 5" ); bput( 6, "строка 6" ); bput( 7, "строка 7" ); bprint(); printf( "Заменяем строку в записи с ключом 2\n" ); bchange( 2, "новая строка 2" ); bprint(); printf( "Заменяем строку в записи с ключом 4\n" ); bchg( 4, "новая строка 4" ); bprint(); printf( "Заменяем строку в записи с ключом 6 и ключ 6 на 8\n" ); i = bget( 6 ); printf( "Сейчас запись с ключом 6 содержит \"%s\"\n", tmp.b_val ); bmod( i, 8, "Новая строка 6/8" ); bprint(); closeBase(); }

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед