|
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 | Нарушение авторских прав
<== предыдущая лекция | | | следующая лекция ==> |