Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Приклад зі списком роззсилки

Читайте также:
  1. A.Прикладной уровень
  2. БЛОК МЕТОДИКО-ПРИКЛАДНЫХ СРЕДСТ.
  3. Відокремлені прикладки та розділові знаки при них
  4. ДЕКОРАТИВНО-ПРИКЛАДНОЕ ИСКУССТВО И НАРОДНЫЕ ПРОМЫСЛЫ
  5. ИСТОРИЯ ЭМПИРИЧЕСКОЙ И ПРИКЛАДНОЙ
  6. Інформатики, прикладної лінгвістики та інших
  7. Кибрик А.Е. Язык // Кибрик А.Е. Очерки по общим и прикладным вопросам языкознания. – М.: Изд-во МГУ, 1992. – С. 9-17.

Щоб показати, як можна легко записувати великі об'єми даних, користуючись функціями fread () і fwrite (), ми розглянемо програму роботи зі списком розсилки. Програма зможе зберігати адреси у файлі. Адреси будуть зберігатися в масиві структур наступного типу:

struct addr

{

char name [30];

char street [40];

char city [20];

char state [3];

unsigned long int zip;

} Addr_list [MAX];

Значення MAX визначає максимальну кількість адрес, що може бути у списку.

При виконанні програми поле name кожної структури ініціалізується порожнім вказівником (NULL). У програмі вільною вважається та структура, поле name якої містить рядок нульової довжини, тобто ім'я адресата являє собою порожнім рядком.

Далі наведені функції save () і load (), які використовуються відповідно для збереження і завантаження бази даних (списку розсилки). Зверніть увагу, наскільки коротко вдалося закодувати кожну з функцій, а адже ця стислість досягнута завдяки потужності fread () і fwrite ()! І ше зверніть увагу на те, як ці функції перевіряють значення, що повертаються функціями fread () і fwrite (), щоб виявити таким чином можливі помилки.

/* Збереження списку. */

void save (void)

{

FILE *fp;

register int i;

if ((fp = fopen ("maillist", "wb")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \n");

return;

}

for (i = 0; i <MAX; i++)

if (*addr_list[i].name)

if (fwrite (&addr_list[i], sizeof (struct addr), 1, fp)!= 1)

printf ("Помилка при записi файлу. \n");

fclose (fp);

}

/* Завантажити файл. */

void load (void)

{

FILE *fp;

register int i;

if ((fp = fopen ("maillist", "rb")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \ n");

return;

}

init_list ();

for (i = 0; i <MAX; i++)

if (fread (&addr_list[i], sizeof (struct addr), 1, fp)!= 1)

{

if (feof (fp)) break;

printf ("Помилка при читаннi файлу. \n");

}

fclose (fp);

}

Обидві функції, save () і load (), підтверджують (або не підтверджують) успішність виконання функціями fread () і fwrite () операцій з файлом, перевіряючи значення, що повертаються функціями fread () і fwrite (). Крім того, функція load () явно перевіряє, чи не досягнуто кінець файлу. Робить вона це за допомогою виклику функції feof (). Це доводиться робити тому, що fread () і в разі помилки, і при досягненні кінця файлу повертає одне і те ж значення.

Далі показана вся програма, що обробляє списки розсилки. Її можна використовувати як ядро для подальших розширень, в неї, наприклад, можна додати засоби пошуку адрес.

/* Проста програма обробки списку розсилки,

в якій використовується масив структур. */

# include <windows.h>

# include <locale.h>

# include <stdio.h>

# include <stdlib.h>

# define MAX 100

 

struct addr

{

char name [30];

char street [40];

char city [20];

char state [20];

unsigned long int zip;

} addr_list [MAX];

void init_list (), enter ();

void delete1 (), list ();

void load (), save ();

int menu_select (), find_free ();

 

int main()

{

setlocale(LC_CTYPE, "Russian");

char choice;

init_list (); /* ініціалізація масиву структур */

for (;;)

{

choice = menu_select ();

switch (choice)

{

case 1: enter (); break;

case 2: delete1 (); break;

case 3: list (); break;

case 4: save (); break;

case 5: load (); break;

case 6: exit (0);

}

}

system ("pause");

return 0;

}

 

/* Ініціалізація списку. */

void init_list ()

{

register int t;

for (t = 0; t <MAX; ++t) addr_list [t].name[0] = '\0';

}

/* Отримання значення, вибраного в меню. */

int menu_select ()

{

char s [80];

int c;

printf ("1. Ввести iм'я \n");

printf ("2. Видалити iм'я \n");

printf ("3. Вивести список \n");

printf ("4. Зберегти файл \n");

printf ("5. Завантажити файл \n");

printf ("6. Вихiд \n");

do

{

printf ("\n Введiть номер потрiбного пункту: ");

gets (s);

c = atoi (s);

} while (c <0 || c> 6);

return c;

}

/* Додавання адреси в список. */

void enter ()

{

int slot;

char s [80];

slot = find_free ();

if (slot == -1)

{

printf ("\n Список заповнений");

return;

}

printf ("Введiть iм'я: ");

gets (addr_list [slot].name);

printf ("Введiть вулицю: ");

gets (addr_list [slot].street);

printf ("Введiть мiсто: ");

gets (addr_list [slot].city);

printf ("Введiть Область: ");

gets (addr_list [slot].state);

printf ("Введiть поштовий iндекс: ");

gets (s);

addr_list [slot].zip = strtoul (s, '\0', 10);

}

/* Пошук вільної структури. */

int find_free ()

{

register int t;

for (t = 0; addr_list[t].name [0] && t <MAX; ++t);

if (t == MAX) return -1; /* вільних структур немає */

return t;

}

/* Видалення адреси. */

void delete1 ()

{

register int slot;

char s [80];

printf ("Введiть № запису: ");

gets (s);

slot = atoi (s);

if (slot >= 0 && slot <MAX)

addr_list [slot].name [0] = '\0';

}

/* Вивід списку на екран. */

void list ()

{

register int t;

for (t = 0; t <MAX; ++t)

{

if (addr_list[t].name [0])

{

printf ("%s \n", addr_list[t].name);

printf ("%s \n", addr_list[t].street);

printf ("%s \n", addr_list[t].city);

printf ("%s \n", addr_list[t].state);

printf ("%lu \n \n", addr_list[t].zip);

}

}

printf ("\n \n");

}

/* Збереження списку. */

void save ()

{

FILE *fp;

register int i;

if ((fp = fopen ("maillist", "wb")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \n");

return;

}

for (i = 0; i <MAX; i++)

if (*addr_list[i].name)

if (fwrite (&addr_list[i], sizeof (struct addr), 1, fp)!= 1)

printf ("Помилка при записi файлу. \n");

fclose (fp);

}

/* Завантажити файл. */

void load ()

{

FILE *fp;

register int i;

if ((fp = fopen ("maillist", "rb")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \ n");

return;

}

init_list ();

for (i = 0; i <MAX; i++)

if (fread (&addr_list[i], sizeof (struct addr), 1, fp)!= 1)

{

if (feof (fp)) break;

printf ("Помилка при читаннi файлу. \n");

}

fclose (fp);

}

 

Функция fseek()

Формат функції:

fseek(fp, n, m);

Ця функція встановлює вказівник у файлі fp в позицію, що відстоїть на n байт від поточної, а напрямок переміщення (вперед або назад) визначається параметром m, який може бути заданий одним з трьох значень: 0, 1, 2 або однією з трьох символьних констант, визначених у файлі stdio.h:

- SEEK_SET = 0 — до початку файлу;

- SEEK_CUR = 1 — вказівник на поточну позицію у файлі;

- SEEK_END = 2 — до кінця файлу.

Функція fseek () використовується для введення/виведення потоком. Для роботи не з потоковими даними слід використовувати функцію lseek (). Після функції fseek () можна виконувати операції оновлення у файлах, відкритих для поновлення. При вдалому завершенні роботи fseek () повертає нуль, в іншому випадку функція повертає код помилки. Тоді глобальна змінна errno приймає одне з наступних значень:

- EBADF - невірний вказівник файлу;

- EINVAL - невірний аргумент функції;

- ESPIPE - пошук на пристрої заборонений.

При прямому доступі можна виконувати операції ведення/виведення, використовуючи систему введення/виведення мови С і функцію fseek (), яка встановлює вказівник поточної позиції у файлі. Ось прототип цієї функції:

int fseek (FILE <вказівник файлу>, long int <кількість_байт>, <початок_відліку>);

кількість_байт - кількість байтів, рахуючи від початок_відліку, воно визначає нове значення вказівника поточної позиції, а початок відліку - це один з наступних макросів:

Початок відліку - Макрос

Початок файлу - SEEK_SET

Поточна позиція - SEEK_CUR

Кінець файлу - SEEK_END

Тому, щоб отримати у файлі доступ на відстані кількість_байт байтів від початку файлу, початок_відліку повинен дорівнювати SEEK_SET. Щоб при доступі відстань відраховувалася від поточної позиції, використовуйте макрос SEEK_CUR, а щоб при доступі відстань відраховувалася від кінця файлу, потрібно вказувати макрос SEEK_END. При успішному завершенні своєї роботи функція fseek () повертає нуль, а в разі помилки - ненульове значення.

У наступній програмі показано, як використовується fseek (). Дана програма в певному файлі відшукує деякий байт, а потім відображає його. У командному рядку потрібно вказати ім'я файлу, а потім потрібний байт, тобто його відстань в байтах від початку файлу.

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

 

int main ()

{

setlocale(LC_CTYPE, "Russian");

FILE * fp;

char ch;

if ((fp = fopen ("testr", "r")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \ n");

system ("pause");

exit (1);

}

fseek (fp, 6, SEEK_SET);

ch=fgetc (fp);

printf ("У 6-му байтi мiститься ");

putchar (ch);

printf ("\n");

fclose (fp);

system ("pause");

return 0;

}

Функцію fseek () можна використовувати для доступу всередині багатьох значень одного типу, просто множачи розмір даних на номер елемента, який вам потрібен. Наприклад, припустимо, є список розсилки, який складається з структур типу addr (визначених раніше). Щоб отримати доступ до десятої адреси у файлі, в якому зберігаються адреси, використовуйте наступний оператор:

fseek (fp, 9 * sizeof (struct addr), SEEK_SET);

Поточне значення вказівника поточної позиції у файлі можна визначити за допомогою функції ftell (). Ось її прототип:

long int ftell (FILE <вказівником файлу>);

Функція повертає поточне значення вказівника поточної позиції у файлі, пов'язаному з вказівником файлу вф. При невдалому результаті вона повертає -1.

Зазвичай прямий доступ може знадобитися лише для двійкових файлів. Причина тут проста - тому що в текстових файлах можуть виконуватися перетворення символів, то може і не бути прямої відповідності між тим, що знаходиться в файлі і тим байтом, до якого потрібен доступ. Єдиний випадок, коли треба використовувати fseek () для текстового файлу - це доступ до тієї позиції, яка була вже знайдена за допомогою ftell (); такий доступ виконується за допомогою макросу SEEK_SET, використовуваного в якості початку відліку.

Добре пам'ятайте наступне: навіть якщо в файлі знаходиться один тільки текст, все одно цей файл при необхідності можна відкрити і в двійковому режимі. Ніякі обмеження, пов'язані з тим, що файли містять текст, до операцій прямого доступу не відносяться. Ці обмеження стосуються лише до файлів, відкритих в текстовому режимі.

Функция ftell()

Формат функції:

long int i = ftell(fp);

Повертає поточне значення вказівника файлу fp (тобто номер поточної позиції) у вигляді значення типу long int. Відлік йде в байтах від початку файлу.

Повернене значення може бути використане потім у функції fseek ().

Якщо виявлені помилки, то функція повертає значення -1L і привласнює глобальній змінній errno додатне значення.

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# include <string.h>

 

int main()

{

setlocale(LC_CTYPE, "Russian");

char str [80];

int i=0;

long int l;

FILE *fp;

if ((fp = fopen ("test", "r")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \n");

system ("pause");

exit(1);

}

while (! feof (fp))

{

l = ftell(fp);

printf ("Номер поточної позицiї %d перед зчитуванням ", l);

fgets (str, 79, fp);

printf (str);

}

l = ftell(fp);

printf ("\n Номер поточної позицiї %d пiсля зчитування ", l);

printf ("\n");

fclose (fp);

system ("pause");

return 0;

}

Функция fscanf()

Формат функції:

fscanf(fp, Control, arg1, arg2,..., argn);

Функція читає дані з файлу з вказівником fp, перетворює їх за форматами, записаними у керуючому рядку Control, і відформатовані дані записує в аргументи arg1,..., аrgn. Докладні відомості про роботу цієї функції можна отримати, ознайомившись з роботою функції scanf () (функцію scanf ()).

Функция fprintf()

Формат функції:

fprinf(fp, Control, arg1, arg2,..., argn);

Виводить дані в файл з вказівником fp, перетворює аргументи arg1,..., аrgn до форматів, які записані в керуючому рядку Control, і відформатовані дані записує в файл. Докладні відомості про роботу цієї функції можна отримати, ознайомившись з роботою функції printf ().

Крім основних функцій введення/виведення, про які йшла мова, в системі введення/виведення мови С також є функції fprintf () і fscanf (). Ці дві функції, за винятком того, що призначені для роботи з файлами, ведуть себе точно так само, як і printf () та scanf (). Прототипи функцій fprintf () і fscanf () наступні:

int fprintf (FILE * вф, const char * керуючий_рядок,...);

int fscanf (FILE * вф, const char * керуючий_рядок,...);

де вф - вказівник файлу, що повертається в результаті виклику fopen (). Операції введення/виведення функції fprintf () і fscanf () виконують з тим файлом, на який вказує вф.

В якості прикладу пропонується розглянути наступну програму, яка читає з клавіатури рядок і ціле значення, а потім записує їх у файл на диску; ім'я цього файлу – test1. Після цього програма читає цей файл і виводить інформацію на екран. Після запуску програми перевірте, яким вийде файл test1. Як ви і побачите, в ньому буде цілком легкий для читання текст.

/* Приклад використання fscanf () і fprintf () */

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

 

int main ()

{

setlocale(LC_CTYPE, "Russian");

FILE *fp;

char s [80];

int t;

if ((fp = fopen ("test1", "w")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \ n");

system ("pause");

exit (1);

}

printf ("Введiть рядок i число: ");

fscanf (stdin, "%s %d", s, &t); /* читати з клавіатури */

fprintf (fp, "%s %d", s, t); /* писати в файл */

fclose (fp);

if ((fp = fopen ("test1", "r")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \n");

system ("pause");

exit (1);

}

printf("\n");

fscanf (fp, "%s %d", s, &t); /* читання з файлу */

fprintf (stdout, "%s %d", s, t); /* виведення на екран */

printf("\n");

fclose (fp);

system ("pause");

return 0;

}

Маленьке попередження. Хоча читати різносортні дані з файлів на дисках і писати їх у файли, розташовані також на дисках, часто легше всього саме за допомогою функцій fprintf () і fscanf (), але це не завжди найефективніший спосіб виконання операцій читання і запису. Так як дані в форматі ASCII записуються так, як вони повинні з'явитися на екрані (а не в двійковому вигляді), то кожен виклик цих функцій пов'язаний з певними накладними витратами. Тому, якщо треба піклуватися про розмір файлу або швидкості, то, швидше за все, доведеться використовувати fread () і fwrite ().

Функция rewind()

Формат функції:

rewind(<вказівник_на_файл>);

Встановлює вказівник поточної позиції у файлі на початок файлу. Виклик функції rewind (<вказівник_на_файл>) відповідає виклику функції fseek (<вказівник_на_файл>, 0L, SEEK_SET) за винятком того, що rewind () скидає індикатор кінця файлу і індикатори помилок, а fseek () скидає тільки індикатор кінця файлу. Після функції rewind () можна виконувати операції оновлення для файлів, відкритих для поновлення. Функція не повертає ніякого значення.

Щоб познайомитися з rewind (), змінимо програму, розглянуту раніше, таким чином, щоб вона відображала вміст файлу відразу після його створення. Щоб виконати відображення, програма після завершення введення "перемотує" файл, а потім читає його з самого початку. Зверніть увагу, що зараз файл необхідно відкрити в режимі читання/запису, використовуючи як аргумент режим, що задає рядок "w+".

 

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# include <string.h>

 

int main()

{

setlocale(LC_CTYPE, "Russian");

char str [80];

FILE *fp;

if ((fp = fopen ("TEST", "w+")) == NULL)

{

printf ("Помилка при вiдкриттi файлу. \ n");

system ("pause");

exit(1);

}

do

{

printf ("Введiть рядок (порожнiй рядок - для виходу): \n");

gets (str);

strcat (str, "\n"); // додавання роздільника рядків

fputs (str, fp);

} while (strcmp("\n", str)); // strcmp() - порівняння рядків

/* Тепер виконується читання і відображення файлу */

rewind (fp); /* встановити вказівник поточної позиції на початок файлу. */

while (! feof (fp))

{

fgets (str, 79, fp);

printf (str);

}

fclose (fp);

system ("pause");

return 0;

}

 

Функция remove()

Формат функції:

int remove (< ім'я_файлу>);

Функція видаляє файл з ім'ям FILENameString. Перед видаленням файл повинен бути закритий. Рядок FILENameString повинен містити повний шлях до файлу. При нормальному завершенні завдання функція повертає нуль, а в разі помилки – 1 (ненульове значення). При цьому глобальна змінна errno приймає наступні значення:

- EACCES - заборонено видаляти;

- ENOENT - немає такого файлу або директорії.

Наступна програма вилучає файл. Однак спочатку вона дає можливість передумати. Утиліта, подібна цій, може стати в нагоді комп'ютерним користувачам-новачкам.

/* Подвійна перевірка перед вилученням. */

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# include <ctype.h>

 

int main()

{

setlocale(LC_CTYPE, "Russian");

char str [80];

char filename[20]={"test"};

printf ("Вилучити файл test? (y/n):");

gets (str);

if (toupper (*str) == 'y')

remove (filename);

if (remove (filename))

{

printf ("Не можна вилучити файл. \n");

system ("pause");

exit (1);

}

system ("pause");

return 0;

}

 

Функция FILElength()

Формат функции:

long FILElength(fp);

Функція повертає довжину файлу з вказівником fp в байтах. Для роботи функції потрібно підключити файл io.h. У випадку помилки функція повертає - 1, та глобальна змінна errno набуває значення EBADF - невірний вказівник файлу.

Функция ferror()

Формат функції:

ferror(fp);

Функція ferror() визначає, чи відбулася помилка під час виконання операції з файлом. Прототип цієї функції наступний:

int ferror(FILE < вказівник_файлу >);

Функція повертає значення true (істина), якщо при останній операції з файлом сталася помилка, в іншому ж випадку вона повертає false (неправда). Так як при будь-якій операції з файлом встановлюється своя умова помилки, то після кожної такої операції слід одразу викликати ferror (), а інакше дані про помилці можуть бути втрачені.

У наступній програмі показано застосування ferror (). Програма видаляє табуляції з файлу, замінюючи їх пробілами. Розмір табуляції визначається макросом TAB_SIZE. Зверніть увагу, що ferror () викликається після кожної операції з файлом.

/* Програма замінює в текстовому файлі символи табуляції пробілами і відслідковує помилки. */

# include <stdlib.h>

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# define IN 0

# define OUT 1

void err (int e);

 

int main()

{

setlocale(LC_CTYPE, "Russian");

FILE *in, *out;

int i;

char ch;

if ((in = fopen ("testr", "rb")) == NULL)

{

printf ("Не можна вiдкрити файл testr. \n");

system ("pause");

exit(1);

}

if ((out = fopen ("testw", "wb")) == NULL)

{

printf ("Не можна вiдкрити файл testw. \n");

system ("pause");

exit(1);

}

do

{

ch = fgetc (in);

if (ferror (in)) err (IN);

/* Якщо знайдена табуляція, виводиться пробіл */

if (ch == '\t')

{

putc (' ', out);

if (ferror (out)) err (OUT);

}

else

{

putc (ch, out);

if (ferror (out)) err (OUT);

}

} while (!feof (in));

fclose (in);

fclose (out);

system ("pause");

return 0;

}

 

void err (int e)

{

if (e == IN) printf ("Помилка при введеннi. \n");

if (e == OUT) printf ("Помилка при виведеннi. \n");

system ("pause");

exit (1);

}

 

Функция freopen()

Формат функції:

FILE *freopen(const char *FILEname, const char *mode, FILE *stream);

Функція підставляє файл, заданий в першому параметрі, замість уже відкритого потоку. Вона закриває потік незалежно від того, чи відкритий він. Ця функція корисна для заміни файлу, пов'язаного зі стандартними пристроями введення/виведення stdin, stdout або stderr. Способи відкриття файлу аналогічні функції fopen (). При успішному завершенні функція повертає вказівник типу FILE (як і функція fopen ()), при неуспішному - NULL.

Приклад перенаправлення потоку за допомогою функції freopen () наведено в лістингу 1.


Дата добавления: 2015-07-10; просмотров: 176 | Нарушение авторских прав


Читайте в этой же книге: Причины и специфика проявления агрессивности детей на разных стадиях подросткового возраста | Половозрастные особенности проявления агрессивности в поведении детей подросткового возраста | Профилактика и коррекция агрессивного поведения | МЕТОДИКА КОРРЕКЦИИ АГРЕССИВНОГО ПОВЕДЕНИЯ В ПОДРОСТКОВОМ ВОЗРАСТЕ | Мероприятия по коррекции агрессии в подростковом возрасте | Анализ проявлений различных форм агрессивности у подростков 10-15 лет | Анализ проявлений различных форм агрессивности у подростков из семей учителей, врачей, инженеров | Опросник уровня агрессивности Басса - Дарки | Опросник | Введення/виведення файлів |
<== предыдущая страница | следующая страница ==>
Функції для роботи з файлами| Функції стандартного введення/виведення

mybiblioteka.su - 2015-2024 год. (0.077 сек.)