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

Тема 13. Стандартные библиотеки языка Си 3 страница



int main(void)

{

float f = 2.0134;

fprintf(stdprn, "\n Это сообщение распечатается на принтере.\r\n");

fprintf(stdprn, "And now some numbers:\r\n");

fprintf(stdprn, "The square of %f is %f.", f, f*f);

fprintf(stdprn, "\f");

return 0;

}

Результат:

Следующие строки распечатаются на принтере

Цифры также выведутся на принтер:

Квадрат 2.013400 это 4.053780

ПРИМЕЧАНИЕ

Чтобы использовать поток stdprn, необходимо отказаться от совместимости с ANSI в вашем компиляторе. Обратитесь к документации компилятора за более подробной информацией. Поскольку поток stdprn не определен в стандарте ANSI, не каждый компилятор его поддерживает.

Пример: escape.c - использование специальных символов в функции printf()

#include <stdio.h>

#define QUIT 3

int get_menu_choice(void);

void print_report(void);

int main(void)

{

int choice = 0;

while (choice!= QUIT)

{

choice = get_menu_choice();

if (choice == 1)

printf("\nBeeping the computer\a\a\a");

else

{

if (choice == 2)

print_report();

}

}

printf("You chose to quit!\n");

return 0;

}

int get_menu_choice(void)

{

int selection = 0;

do

{

printf("\n");

printf("\n1 - Beep Computer");

printf("\n2 - Display Report");

printf("\n3 - Quit");

printf("\n");

printf("\nEnter a selection:");

scanf("%d", &selection);

}while (selection < 1 || selection > 3);

return selection;

}

void print_report(void)

{

printf("\nSAMPLE REPORT");

printf("\n\nSequence\tMeaning");

printf("\n=========\t=======");

printf("\n\\a\t\tbell (alert)");

printf("\n\\b\t\tbackspace");

printf("\n...\t\t...");

}

РЕКОМЕНДУЕТСЯ

Используйте функцию fprintf() при написании ваших программ, посылающих целевой вывод в поток stdout, stderr, stdprn.

Пример: num.c - ввод числовых значений с помощью функции printf()

#include <stdio.h>

int a = 2, b = 10, c = 50;

float f = 1.05, g = 25.5, h = -0.1;

int main(void)

{

printf("\nDecimal values without tabs: %d %d %d", a, b, c);

printf("\nDecimal values with tabs: \t%d \t%d \t%d", a, b, c);

printf("\nThree floats on 1 line: \t%f\t%f\t%f", f, g, h);

printf("\nThree floats on 3 lines: \n\t%f\n\t%f\n\t%f", f, g, h);

printf("\nThe rate is %f%%", f);

printf("\nThe result of %f/%f = %f\n", g, f, g / f);

return 0;

}

Результат:

Decimal values without tabs: 2 10 50

Decimal values with tabs: 2 10 50

Three floats on 1 line: 1.050000 25.500000 -0.100000

Three floats on 3 line:

1.050000

25.500000

-0.100000

The rate is 1.050000%

The result of 25.500000/1.050000 = 24.285715

СОВЕТ

 

Для более подробного ознакомления с функциями форматированного ввода-вывода обратитесь к справочной системе Си.

13.4. Последовательный и прямой доступ в поток

 

Операции чтения и записи для потока начинается с текущей позиции потока, определяемой указателем потока. Начальная позиция указателя потока устанавливается при открытии потока и может указывать на начало в режиме доступа «r» и «w», и на конец - в режиме «а».

 

После выполнения операции чтения или записи указатель потока изменяется и отражает новую текущую позицию потока, это т.н. последовательный доступ



 

Указатель потока можно позиционировать на любое место в потоке, т.е. осуществлять прямой доступ

 

Для управления указателем потока используются следующие функции:

· ftell(); или fgetpos(); - определяют текущую позицию указателя потока

· fseek(); или fsetpos(); - устанавливают указатель потока в заданную позицию

· rewind(); - устанавливает указатель потока в начальную позицию

Формат:

void rewind (FILE * имя_указателя );

Формат:

int fseek (FILE * имя_указателя, long колич_байт, int из_положения );

 

где

имя_указателя – это указатель, ссылающийся на соответствующий файл.

 

Данная функция сдвигает указатель потока на число байт, равное аргументу колич_байт от точки отсчета, задаваемой аргументом из_положения.

 

 

ПРИМЕЧАНИЕ

Если параметр колич_байт >0, то указатель потока сдвигается в сторону конца файла.

Если параметр колич_байт <0, то указатель потока сдвигается в сторону начала файла.

 

 

Аргумент из_положения – это один из макросов, определенных в «stdio.h», определяющих точку отсчета для сдвига и может принимать одно из следующих значений:

· SEEK_SET - начало потока

· SEEK_CUR - текущая позиция потока

· SEEK_END -конец потока).

 

В случае успеха функция fseek() возвращает ноль, а при ошибке – EOF.

 

Пример:

FILE *fp;

long n;

fp= fopen (“dat”,”r”);

n=14;

fseek (fp, n, SEEK_SET);

fseek (fp, 0L, SEEK_SET);

fseek (fp, -n, SEEK_END); // n-й элемент с конца

 

Пример: функция для чтения группы байтов с заданной позиции потока

int readbytes (FILE *fp, long pos, int n, char *save)

{

int num=-1;

if (fseek (fp, pos, SEEK_SET)==0)

num=fread (save, 1, n, fp);

return num;

}

 

Для определения текущей позиции потока используется функция ftell().

 

Формат:

long ftell (FILE * имя_указателя );

 

Данная функция возвращает текущее значение указателя записи/чтения, который имеет тип longint. В случае ошибки функция возвращает «-1» типа long, т.е. «-1L».

 

При использовании fseek() и ftell() следует учитывать преобразование символа ‘ \n ’ в два символа – «возврат каретки» и «перевод строки». Поэтому, задавая значения параметров функции fseek() или интерпретируя полученные результаты от ftell() следует помнить о дополнительных байтах в файле.

 

Например, запись 10 строк по 20 символов в каждой в поток, открытый в текстовом режиме, даст файл общей длинной (10*20)+10=210 байт (вместо предполагаемых 200 байт), а обращение «fseek(fp, 42, SEEK_SET);» установит указатель потока на конец 2-й строки, а не на начало 3-й.

ВНИМАНИЕ

Нельзя использовать функции определения и установки указателя потока для тех потоков, которые представляют устройства, а применение этих функций к стандартным потокам приведет к неопределенным результатам.

 

Пример: ftell.c - использование функций rewind() и ftell()

#include <stdlib.h>

#include <stdio.h>

#define BUFLEN 6

char msg[] = "abcdefghijklmnopqrstuvwxyz";

int main(void)

{

FILE *fp;

char buf[BUFLEN];

if ((fp = fopen("TEXT.TXT", "w")) == NULL)

{

fprintf(stderr, "Error opening file.");

exit(1);

}

if (fputs(msg, fp) == EOF)

{

fprintf(stderr, "Error writing to file.");

exit(1);

}

fclose(fp);

if ((fp = fopen("text.txt", "r")) == NULL)

{

fprintf(stderr, "Error opening file.");

exit(1);

}

printf("\nImmediately after opening, position = %ld", ftell(fp));

fgets(buf, BUFLEN, fp);

printf("\nAfter reading in %s, position = %ld", buf, ftell(fp));

fgets(buf, BUFLEN, fp);

printf("\n\nThe next 5 characters are %s, and position now = %ld",

buf, ftell(fp));

rewind(fp);

printf("\n\nAfter rewinding, the position is back at %ld",

ftell(fp));

fgets(buf, BUFLEN, fp);

printf("\nand reading starts at the beginning again: %s\n", buf);

fclose(fp);

return 0;

}

Скачать архив [ ftell.c, ftell.exe и text.txt ]

Результат:

Immediately after opening, position = 0

After reading in abcde, position = 5

The next 5 characters are fhig, and position now = 10

After rewinding, the position is back at 0

and reading starts at the beginning again: abcde

Пример: fseek.c - произвольный доступ к файлу при помощи fseek()

#include <stdlib.h>

#include <stdio.h>

#define MAX 50

int main(void)

{

FILE *fp;

int data, count, array[MAX];

long offset;

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

array[count] = count * 10;

if ((fp = fopen("random.dat", "wb")) == NULL)

{

fprintf(stderr, "\nError opening file.");

exit(1);

}

if ((fwrite(array, sizeof(int), MAX, fp))!= MAX)

{

fprintf(stderr, "\nError writing data to file.");

exit(1);

}

fclose(fp);

if ((fp = fopen("RANDOM.DAT", "rb")) == NULL)

{

fprintf(stderr, "\nError opening file.");

exit(1);

}

while (1)

{

printf("\nEnter element to read, 0-%d, -1 to quit: ",MAX-1);

scanf("%ld", &offset);

if (offset < 0)

break;

else if (offset > MAX-1)

continue;

if ((fseek(fp, (offset*sizeof(int)), SEEK_SET))!= 0)

{

fprintf(stderr, "\nError using fseek().");

exit(1);

}

fread(&data, sizeof(int), 1, fp);

printf("\nElement %ld has value %d.", offset, data);

}

fclose(fp);

return 0;

}

Результат:

Enter element to read, 0-49, -1 to quit: 5

Element 5 has value 50.

Enter element to read, 0-49, -1 to quit: 6

Element 6 has value 60.

Enter element to read, 0-49, -1 to quit: 49

Element 49 has value 490.

Enter element to read, 0-49, -1 to quit: 1

Element 1 has value 10.

Enter element to read, 0-49, -1 to quit: 0

Element 0 has value 0.

Enter element to read, 0-49, -1 to quit: -1

13.5. Управление буферизацией

 

Потоки, открываемые функциями ввода-вывода для потоков, по умолчанию буферизируются, т.е. при открытии потока с ним связывается область памяти, называемая буфером.

 

При операции чтения блок данных помещается в буфер, а затем данные читаются из буфера. После обработки входного буфера в него помещается следующий блок данных.

 

При операции записи буфер выгружается (содержание буфера помещается в соответствующий поток) в следующих случаях:

· Буфер заполнен

· Закрывается связанный с ним поток

· При успешном завершении программы

 

Буферизация повышает эффективность ввода-вывода, т.к. ОС передает за одну операцию большие блоки данных, а не выполняет операцию ввода-вывода каждый раз, когда из потока читается (в поток записывается) элемент данных.

 

Размер внутреннего буфера библиотечных функций составляет 512 байт для регулярных файлов и 128 байт – для стандартных файлов. Буферизацией ввода-вывода управляют функции setbuf() и setvbuf(), позволяющие либо отключить буферизацию полностью, либо использовать в качестве буфера область памяти прикладной программы (последнее, дает возможность существенно сократить объем памяти, необходимый программе при выполнении). Эти функции содержатся в «stdio.h».

 

Буферы, предоставленные ОС, пользователю не доступны, а с буферами, распределенные функциями setbuf() и setvbuf(), можно работать как с обычными переменными.

 

Формат:

void setbuf (FILE * имя_указателя, char * буфер );

 

Данная функция связывает поток с буфером, который должен быть массивом символов (размером «BUFSIZ» байт).

Константа BUFSIZ содержится в «stdio.h» и равна 512 байт. Если буфер равен null, то доступ к открытому файлу, на который ссылается указатель * имя_указателя, будет небуферизированный, иначе будет использоваться область памяти размером 512 байт, начиная с адреса, заданного указателем * буфер.

 

 

ПРИМЕЧАНИЕ

Функция setbuf() используется в случае, когда необходимо выключить буферизацию полностью или когда в качестве буфера нужно использовать область памяти программы размером 512 байт.

 

 

Пример:

#include <stdio.h>

main ()

{

FILE *fp;

char mybuf [BUFSIZ];

fp=fopen (“dat.txt”, ”w”);

...

setbuf (fp,mybuf);

...

}

После этого все операции ввода-вывода для потока fp будут выполняться через буфер mybuf, а не через системный буфер.

 

Для отключения буферизации потока fp нужно в вызове функции «setbuf (fp,mybuf);» вместо «mybuf» написать «null».

 

Пример:

#include <stdio.h>

main ()

{

FILE *fp;

char mybuf [BUFSIZ];

fp=fopen (“dat.txt”, ”w”);

...

setbuf (fp,null);

...

}

 

Формат:

int setbuf (FILE * имя_указателя, char * буфер, int тип_буфериз, unsigned размер );

Данная функция позволяет назначить потоку буфер любого размера (но не более 64 кбайт) или увеличить автоматически назначенный размер буфера потоку.

 

Аргумент тип_буфериз определяет тип буферизации потока и может принимать одно из константных значений:

· _IOFBF - поток буферизируется

· _IONBF - поток не буферизируется

· _IOLBF - поток является построчно буферизируемым, т.е. при каждом «\n» происходит выгрузка буфера.

 

В случае успеха функция возвращает ноль и не ноль в противном случае.

 

Пример:

FILE *fp;

char *buf;

unsigned int n;

...

setvbuf (fp, buf, _IOFBF, n); // назначение буфера размером n

setvbuf (fp, buf, _IONBF, n); // отмена буферизации

 

Если в качестве buf использовать «null», то буфер будет распределяться обращением к функции malloc().

 

Пример: setvbuf (fp, null, _IOFBF, 8192);

 

Стандартные потоки stderr и stdaux не буферизируются, но, используя функцию буферизации, их можно сделать буферизированными. Потоки stdin, stdout и stdprn по умолчанию буферизируются. Буфер выгружается, когда он заполнен или когда завершена функция, вызвавшая ввод-вывод.

 

 

ВНИМАНИЕ

При аварийном завершении буфер не выгружается!

 

 

Кроме автоматической выгрузки буфера, его можно выгрузить в любое время с помощью функций fflush() или flushall().

 

Формат:

int fflush (FILE * имя_указателя );

 

Данная функция выгружает буфер открытого потока, на который ссылается указатель * имя_указателя. При этом поток остается открытым. Возвращает в случае успеха ноль и EOF - при ошибке

 

Формат:

int flushall (void);

Данная функция выгружает все буфера связанные с открытыми потоками. Потоки остаются открытыми. Возвращает целое число открытых входных и выходных потоков.

 

 

13.6. Ввод-вывод нижнего уровня

 

Ввод-вывод нижнего уровня относится к небуферизированному неформатированному unix-подобному вводу-выводу.

 

Функции ввода-вывода нижнего уровня прямо вызывают средства ОС. Прототипы этих функций находятся в файле «io.h». Эти функции называются функциями системныхвызовов или процессами нижнего уровня [60].

 

С файловыми открывающимися функциями нижнего уровня связывается дескриптор файла, который представляет собой число, которое использует ОС для ссылки на этот файл.

 

 

13.6.1. Открытие файла

Функции открытия файла:

create () – функция создает новый файл или перезаписывает существующий

open () – функция открывает существующий файл

 

Формат:

int open (const char * имя_файла, int доступ );

Данная функция открывает файл для записи/чтения и возвращает дескриптор файла, который можно присвоить целой переменной и использовать ее для ссылки на файл. Функция в случае успеха возвращает дескриптор файла или «-1» при ошибке.

 

Аргумент доступ задает тип допустимых операций для файла и может принимать одно из находящихся в файле «fcntl.h» константных значений:

· O_APPEND - файл открывается для добавления в конец

· O_BINARY - файл открывается для добавления в конец в двоичном режиме

· O_CREAT - создается и открывается новый файл

· O_RDONLY - создается и открывается новый файл только для чтения

· O_RDWR - создается и открывается новый файл для чтения и записи

· O_TEXT - создается и открывается новый файл в текстовом режиме

· O_TRUNC - открывается существующий файл, а его содержимое удаляется

· O_WRONLY -открывается только для записи существующий файл, а его содержимое удаляется

ПРИМЕЧАНИЕ

Если нужно задать более одной константы, то они связываются последовательно с помощью символа «|».

 

Пример:

int handle;

handle=open (“file.bat”,O_CREAT | O_WRONLY);

 

 

13.6.2. Закрытие файла

Закрытие ранее открытого файла производится с помощью функции close().

 

Формат:

int close (int handle );

Данная функция в случае успеха возвращает ноль и «-1» - при ошибке.

 

Пример:

#include <stdio.h>

#include <io.h>

#include <fcntl.h>

main ()

{

int handle;

...

if ((handle=open (“file”, O_RDONLY)==-1)

fprintf (stderr, “Невозможно открыть файл!”);

...

close (handle);

}

 

 

13.7. Переопределение файлов и потоков

 

С началом выполнения любой программы автоматически открываются пять файлов (потоков), с которыми связаны дескрипторы.

 

Таблица 2

Дескриптор

Поток (файл)

 

stdin

 

stdout

 

stderr

 

stdaux

 

stdprn

 

С помощью этих дескрипторов программа может иметь доступ к стандартным файлам. Можно определить и дескрипторы, связанные с любым потоком, с помощью функции fileno() из библиотеки «stdio.h».

 

Формат:

int fileno (FILE * имя_указателя );

 

Данная функция возвращает дескриптор файла, на который ссылается указатель * имя_указателя.

 

Если поток имеет несколько дескрипторов, то возвращается тот, который связывается с потоком при первичном открытии файла. Одному и тому же файлу можно назначить несколько дескрипторов с помощью функций dup() и dup2(). Обычно они используются для переадресации обмена со стандартными файлами ввода-вывода.

 

Формат:

int dup (int дескриптор );

 

Данная функция назначает новый дескриптор файлу с дескриптором дескриптор. В случае успеха функция возвращает новый дескриптор, а при ошибке – «-1».

 

 

НЕ РЕКОМЕНДУЕТСЯ

Не пытайтесь перенаправить поток stderr.

Не используйте поток stderr для каких либо других целей, кроме вывода предупреждений и сообщений об ошибках.

 

 

Во внутренней таблице открытых файлов системы отыскивается новый свободный элемент, в который копируется элемент внутренней таблицы с порядковым номером дескриптор. В результате в таблице появится два элемента, которые ссылаются на один и тот же файл.

 

Пример: назначение нового дескриптора потоку

#include <stdio.h>

#include <io.h>

int newhandle (FILE *fp)

{

int new;

if ((new=dup (fileno (fp)))==-1)

printf (“нельзя назначить новый дескриптор потоку\n”);

return new;

}

main ()

{

FILE *fptr;

int newhndl;

...

newhndl=newhandle(fptr)

}

 

Формат:

int dup2 (int стар _ дескриптор, int нов _ дескриптор );

 

Данная функция копирует информацию о файле с дескриптором стар _ дескриптор в строку таблицы файлов с номером нов _ дескриптор. Если эта строка таблицы была отведена под другой файл или устройство, то они закрываются. В случае успеха функция возвращает ноль, а при ошибке – «-1».


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







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







<== предыдущая лекция | следующая лекция ==>