Программирование >>  Процедурные приложения 

1 ... 58 59 60 [ 61 ] 62 63 64 ... 150


Глава 10. Ввод-вывод в языке С

Потоковые функции

o Открытие файлов и потоков o Переадресация ввода-вывода o Изменение буфера потока o Закрытие файлов и потоков

Низкоуровневый ввод-вывод

Ввод-вывод символов

o Функции getc (), putc (), fgetc () и iputc()

o Функции getchar() , putchar (), fgetchar () и fputchar ()

o Функции getch(), getche() и putch()

Ввод-вывод строк

o Функции gets(), puts(), fgets() и fputs()

Ввод-вывод целых чисел

o Функции getw () и putw ()

Форматный вывод данных

o Функция printf ()

Поиск в файлах с помощью функций fseek() , ftell () и rewind()

Форматный ввод

o Функции scanf (), fscanf() и sscanf ()

Большинство популярных языков программирования высокого уровня имеет довольно ограниченные средства ввода-вывода. В результате программистам часто приходится разрабатывать изощренные алгоритмы, чтобы добиться необходимых результатов при вводе или выводе данных. К счастью, это не относится к языку С, который снабжен мощной подсистемой ввода-вывода, представленной обширной библиотекой соответствующих функций, хотя исторически эта подсистема не была частью языка. Как бы то ни было, те программисты, которые привыкли в языке Pascal использовать только два оператора - readln и writeln, - будут поражены обилием функций ввода-вывода в языке С. В настоящей главе мы рассмотрим более 20-ти различных способов ввода и вывода информации, существующих в С.

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

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

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



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

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

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

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

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

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

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

Потоковые функции

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

Многие константы, содержащиеся в файле STDIO.H, находят достаточно широкое применение в приложениях. Например, константа eof возвращается функциями ввода при достижении конца файла, а константа null служит нулевым ( пустым ) указателем. Другие примеры: тип данных file представляет собой структуру, содержащую информацию о потоке, а константа BUFSIZ задает стандартный размер в байтах буфера, используемого потоком.

Открытие файлов и потоков

Чтобы открыть файл для ввода или вывода данных, воспользуйтесь одной из следующих функций: fopen(),fdopen() или freopen() Файл открывается для чтения, записи или для



выполнения обеих операций. Кроме того, файл может быть открыт в текстовом или в двоичном режиме.

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

pfinfile = fopen( input.dat , r );

При запуске приложения автоматически открываются сразу пять стандартных потоков: ввода (stdin), вывода (stdout), ошибок (stderr), печати (stdprn) и внешнего устройства (stdaux). По умолчанию стандартные потоки ввода, вывода и ошибок связаны с консолью. Например, данные, записываемые в стандартный вывод, выводятся на терминал. Любое сообщение об ошибке, сгенерированное библиотечной функцией, также выводится на терминал. Потоки stdprnи stdaux направляют данные соответственно в порт принтера и порт внешнего устройства.

Во всех функциях, где в качестве аргумента требуется указатель на поток, можно использовать любой из перечисленных выше указателей. Некоторые функции, такие как getchar() и putchar(), работают только с потоками stdinи stdout. Поскольку указатели stdin, stdout, stderr, stdprn и stdaux являются константами, а не переменными, не пытайтесь переадресовать их на другие потоки.

Переадресация ввода-вывода

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

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

Например, в командной строке MS-DOS переадресация выполняется очень просто. Вы используете оператор < для переадресации ввода и > для переадресации вывода. Допустим, исполняемый файл вашего приложения называется REDIRECT. Тогда следующая команда сначала запустит программу REDIRECT, а затем инициирует ввод данных из файла SAMPLE.DAT вместо стандартного ввода с клавиатуры:

redirect< sample.dat

Следующая строка одновременно осуществит переадресацию ввода из файла SAMPLE.DATи переадресацию вывода в файл SAMPLE.BAK:

redirect < sample.dat > sample.bak

И наконец, последняя строка переадресует только вывод данных:

redirect > sample.bak

Стандартный поток ошибок stderr не может быть переадресован.

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

Для того чтобы связать каналом стандартный ввод одной программы и стандартный вывод другой, следует поставить символ вертикальной черты ():

process1 process2

Все детали по организации взаимодействия систем ввода-вывода двух программ PROCESS1 и PROCESS2 берет на себя операционная система.

Изменение буфера потока



1 ... 58 59 60 [ 61 ] 62 63 64 ... 150

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика