Ввод данных в языке Си. Функция scanf
Основная задача этого шага научиться получить данные от пользователя.
Для этого можно использовать функцию scanf . Она, так же как и функция printf , описана в заголовочном файле stdio.h . Т.к. он у нас уже подключен в первой строке, то мы можем свободно использовать функцию scanf в своей программе.
Чтобы считать данные, которые ввёл пользователь, и сохранить их в переменную, нужно вызвать функцию scanf со следующими параметрами:

Рис.1. Общий синтаксис функции scanf.
В двойных кавычках указывается спецификатор формата. В зависимости от того в какую переменную мы собираемся сохранять введенное значение, необходимо использовать соответствующий спецификатор формата.
Основные спецификаторы формата:
%d — целые числа
%f — вещественное число типа float
%lf — вещественное число типа double (обозначение lf от long float)
%c — символ
Обратите внимание, что в функции scanf для типов float и double используются различные спецификаторы формата.
После формат-строки нужно указать адрес переменной, в которую нужно сохранить данные. Чтобы указать адрес переменной достаточно перед её именем записать знак & (амперсанд), как на рисунке выше.
Напишем, наконец-таки, программу сложения двух чисел.
#include int main(void) < int a, b, res; scanf("%d", &a); // считываем целое значение в переменную a scanf("%d", &b); // считываем целое значение в переменную b res = a + b; printf("%d + %d = %d\n", a, b, res); return 0; >
Скомпилируйте и запустите эту программу. После того, как программа запущена она будет ждать пока вы введёте данные. Мы с вами знаем какие данные нужно вводить, т.к. мы писали эту программу. Для других пользователей, которые код программы не увидят, хорошо бы вывести на экран подсказку, какие данные нужно ввести. Посмотрите как это реализовано в следующем примере.
Эта программа будет полезна тем, кто следит за своим здоровьем. Данная программа подсчитывает уроверь базового обмена веществ по формуле Миффлина-Сан Жеора исходя из данных, которые вы введёте (возраст, рост и вес).
#include int main(void) < int age, height, weight; double bov_m, bov_f; printf("Vash vozrast?(god)\n"); scanf("%d", &age); // считываем целое значение в переменную age printf("Vash rost?(cm)\n"); scanf("%d", &height); // считываем значение в переменную height printf("Vash ves?(kg)\n"); scanf("%d", &weight); // считываем значение в переменную weight bov_m = 10*weight + 6.25*height - 5*age + 5; bov_f = 10*weight + 6.25*height - 5*age - 161; printf("| BMR |\n"); printf("| male | female |\n"); printf("|%8.2f|%8.2f|\n",bov_m, bov_f); return 0; >
На самом деле, функция scanf – функция форматного ввода. Она устроена чуть ли не сложнее, чем printf . Но рассказывать новичку об особенностях её работы значит понапрасну грузить его лишней информацией. На данном этапе вам будет достаточно и этих знаний, а когда появится необходимость использовать что-то большее, вы с этим сможете сами разобраться. А может и я в каком-нибудь уроке расскажу.
Сохрани в закладки или поддержи проект.
Практика

Решите предложенные задачи. Для удобства работы сразу переходите в полноэкранный режим
Исследовательские задачи для хакеров:
- Попробуйте удалить в программе Листинг 2 символ & в какой-нибудь функции scanf . Посмотрите какую ошибку выдаст компилятор.
- Попробуйте использовать %f для типа double , а %lf для типа float . Каковы результаты? Напишите об этом в комментариях к этому уроку. Не забудьте указать название вашей IDE или компилятора.
Дополнительные материалы
- пока нет
Самый крупный донат:
sdanshin@yandex.ru 5000 руб.
Аноним, Юmoney * 9482 1960 руб.
Руслан Викторович П, +7(985) ***-**-99 1000 руб.
Сергей Евгеньевич С, +7 (977) ***-**-40 500 руб.
Оставить комментарий
Чтобы код красиво отображался на странице заключайте его в теги [code] здесь писать код [/code]
Комментарии
Сергей 09.12.2017 в 14:58
Здраствуйте мне нужна помощь :когда я задаю значение float он в ответе пишет так : 3.50 + 3.40 = 6.9000000
Как убрать нолики?
KaDeaT
Об этом рассказывается в уроке Форматированный вывод.
Посмотрите на листинг 8 и на результат вывода.
Дмитрий 15.12.2017 в 00:09
Нет возможности в некоторых темах сохранить урок ввиде PDF файла для изучения в offline когда летишь в самолёте! Создайте пожалуйста одну общую кнопку для сохранения уроков в режиме ,offline пожалуйста
KaDeaT
Дмитрий, добрый день. Да, знаю об этой проблеме.
К сожалению не хватает времени сделать pdf-версии для всех уроков. Но оно обязательно будет, обещаю. Не могу быть уверенным, что к концу этого года успею, но уж в январе 2018 pdf-версия будет у каждого урока.
Кирилл 03.01.2018 в 20:18
Здравствуйте, появился вопрос: почему при выводе переменных в printf мы не используем знак «&», хотя в вводе scanf он необходим?
Заранее большое спасибо
KaDeaT
Добрый день.
Это одна из особенностей того, как устроены функции в языке Си.
Функции не могут изменять те переменные, которые им передаются. Чтобы они могли изменять эти переменные, надо им передавать не переменную, а адрес в памяти где хранится переменная. Поэтому для printf, которая просто выводит переменную на экран не изменяя её, нужно передавать только имя переменной, а для scanf, которая записывает в переменную данные, тем самым изменяя её, нужно передавать адрес в памяти.
Чтобы получить адрес переменной, нужно использовать операцию &.
DimaKotoriyRAshid 08.01.2018 в 23:32
У меня никак не получается сделать предпоследнее задание , постоянно выдает ошибку номер 2. При правильном ответе он пишет какую то откровенную дич. Уже битый час пытаюсь найти ошибку ((9(
KaDeaT
Пожалуйста, напишите в комментариях на Stepik номер своего решения. Попробую вам помочь.)
Андрей 21.03.2018 в 21:16
«но уж в январе 2018 pdf-версия будет у каждого урока» это цитата из комментария))
Я не могу найти эту кнопку.
KaDeaT
Дела и заботы, к сожалению, помешали сбыться этому плану. Никак не могу взяться за эту работу. Но возьмусь летом, а может даже раньше.
Farid 28.06.2018 в 17:09
ya reshil vse zadaci,pishu kuski sekretnogo klyuca,no mne pishut neverniy klyuc.mojete proveryat?
KaDeaT
Проверил, всё работает правильно. Может быть вы не удалили пробелы? Пробелов быть не должно.
Виталий 07.08.2018 в 04:48
* а когда появится необходимость использовать что-то большее, вы с этими сможете сами разобраться — очепятка ~вы с ЭТИМ сможете~
KaDeaT
Спасибо. Поправил!
Samvel 26.08.2018 в 07:40
1 + -365906032 = 803628530
Eclipse
KaDeaT
Николай Евсюков 27.08.2018 в 18:26
1. CRT: unhandled exception (main) — terminating
*** Process returned 255 ***
2. float f;
double d;
scanf(«%lf», &f);
scanf(«%f», &d);
printf(«%f %f», f, d);
Ввод:
1.1
2.2
Вывод:
-0.000000 0.000000
P.S. IDE Pelles C.
KaDeaT
Krowka_v_Kartowke 05.11.2018 в 23:59
Здравствуйте, нашел опечатку. «Скомпилируйте и запустить(*те) эту программу.». Урок отличный, спасибо Вам.
KaDeaT
Спасибо за внимательность! Поправил.
не_робот_я 17.02.2019 в 11:27
хакерские задачи:
1. сегфолт (ошибка сегментации)
2. Xcode ругается так «Format specifies type ‘float *’ but the argument has type ‘double *'», а онлайн компилятор onlinegdb.com не ругается, но результат выдаёт нулевой.
KaDeaT
Estel 05.03.2019 в 15:16
Отличные уроки, большое спасибо!
по заданию 1:
Variable ‘dollars’ is uninitialized when used here
Initialize the variable ‘dollars’ to silence this warning
по заданию 2:
Format specifies type ‘float *’ but the argument has type ‘double *’
Format specifies type ‘double *’ but the argument has type ‘float *’
(Xcode)
KaDeaT
Максим 14.04.2019 в 15:38
Использую Dev C++.
1. Если удалить адрес из какой-либо переменной, она на выводится на экран, при нажатии на клавишу.
2. Если использовать спецификатор %f для типа double, выводимый результат будет 0.00000+0.00000=0.00000.
3. Если использовать спецификатор %lf для типа floai, второе слагаемое будет всегда 0.00000, а первое будет выдавать неверно введенные данные.
pchristi 02.07.2019 в 08:35
Поэкспериментировал со второй хакерской задачкой. Вводил число 3.14 потом 1.12;
В первом случае при %f и double в printf был такой результат:
1) 512181179925964090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000.000000
2) 512181179185108140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000.000000
Во втором случае, при %lf и типе float вышло так:
1) 126443839488.000000
2) 0.000000
Александр 30.09.2019 в 12:27
Не одобряю примеры на данной странице, так как в них начальные значения переменным не задаются. Это очень плохой стиль программирования: если в реальной жизни забудешь дальше выполнить присваивание значения, новичок может долго отлаживаться, чтобы понять, в чём проблема.
Как найти ввод исходных данных в c
По умолчанию язык C++ не содержит встроенных средств для ввода с консоли и вывода на консоль, эти средства предоставляются библиотекой iostream . В ней определены два типа: istream и ostream . istream представляет поток ввода, а ostream — поток вывода.
Вообще, сам термин «поток» в данном случае представляет последовательность символов, которая записывается на устройство ввода-вывода или считывается с него. И в данном случае под устройством ввода-вывода рассматривается консоль.
Для записи или вывода символов на консоль применяется объект cout , который представляет тип ostream. А для чтения с консоли используется объект cin
Для использования этих объектов в начало исходного файла необходимо подключить библиотеку iostream:
#include
Вывод на консоль
#include int main() < int age ; double weight ; std::cout
Консольный вывод программы:
Name: Tom Age: 33 Weight: 81.23
Строки могут содержать управляющие последовательности, которые интерпретируются определенным образом. Например, последовательность «\n» интерпретируется как перевод на новую строку. Из других управляющих последовательностей также нередко употребляется «\t», которая интерпретируется как табуляция.
Ввод с консоли
Для считывания с консоли данных применяется оператор ввода >> , который принимает два операнда. Левый операнд представляет объект типа istream (в данном случае объект cin), с которого производится считывание, а правый операнд — объект, в который считываются данные.
Например, считаем данные с консоли:
#include int main() < int age; double weight; std::cout > age; std::cout > weight; std::cout
Здесь после приглашений к вводу программа ожидает ввода значений для переменных age и weight.
Пример работы программы:
Input age: 32 Input weight: 67.45 Age: 32 Weight: 67.45
Стоит отметить, что так как оператор ввода в первом случае будет добавлять данные в целочисленную переменную age, то он ожидает ввода числа. В случае с переменной weight оператор ввода ожидает число с плавающей точкой, причем разделителем целой и дробной части должна быть точка. Поэтому мы не можем ввести любые значения, например, строки. В этом случае программа может выдать некорректный результат.
Оператор ввода >> возвращает левый операнд — объект cin, поэтому мы можем по цепочке считывать данные в различные переменные:
#include int main() < int age; double weight; std::cout > age >> weight; std::cout
Пример работы программы:
Input age and weight: 32 67.45 Age: 32 Weight: 67.45
После ввода одного из значений надо будет ввести пробел и затем вводить следующее значение.
Как найти ввод исходных данных в c
Интуитивное определение файла звучит примерно так. Файл — именованная область на жестком диске. На самом деле с точки зрения ОС UNIX это совсем не так. В ОС UNIX файл — очень удобная абстракция. С точки зрения UNIX файлом называется «что-нибудь», из чего можно считывать информацию или во что можно записывать информацию. Файлы это:
- Файлы в обычном смысле: файлы, которые хранятся на жестком диске (можно считывать из них и запиcывать в них информацию);
- Экран монитора: файл, в который можно выводить информацию (отобразится на экране монитора);
- Клавиатура: файл, из которого можно считывать информацию;
- Принтер: файл, в который можно выводить информацию (печать текста);
- Модем: файл, из которого можно считывать информацию и в который можно записывать информацию (обмен информации по сети);
0.2 Разделение понятий файла и названия
Неправильно думать, что между сущностями «файл» и «название файла» есть взаимно однозначное соответствие.
Можно привести аналогию из жизни: если представить, что файл — это банка с некоторым содержимым, то название файла — это этикетка на этой банке. Логично предположить, что у банки может быть несколько этикеток.
С точки зрения UNIX:
Правильно говорить, что у названия есть файл. И наоборот: неправильно говорить, что у файла есть название. Никакого эффективного способа узнать имя файла не существует (но можно перебрать все файлы файловой системы).
0.3 Функции link и unlink
Пусть есть файл file1.txt . Для его удаления используется функция:
int unlink(const char* filename);
Эта функция не всегда удаляет файл (с жесткого диска), а только удаляет «этикетку» этого файла. Если есть другая «этикетка» этого файла, то файл останется на жестком диске; просто у него уже не будет этой «этикетки». Файл знает, сколько у него таких «этикеток» (есть специальный счетчик). И если этот счетчик стал равен нулю, то функция удаляет файл с жесткого диска. В ОС Windows эта функция всегда удаляет файл.
Парная функция к этой функции:
int link(const char* filename1, const char* filename2);
Эта функция создает еще одну «этикетку» для этого файла и прибавляет к значению счетчика «этикеток» единицу.
1 Ввод и вывод, язык C, структура FILE
1.1 Чтение и запись: printf и scanf
Всем хорошо известная функция printf :
printf(«Hello!») — печать текста на экран;
printf(«N = %d», N) — форматированный вывод на экран: вывести число N в десятичной записи;
printf(«N = %x», N) — форматированный вывод на экран: вывести число N в шестнадцатеричной записи;
Аналогично парная функция scanf :
char *ptr = new char[10];
scanf(«%s», ptr); — считывание с клавиатуры строки в массив *ptr
char *ptr = new char[10];
scanf(«%s», ptr);
Тут налицо потенциальная проблема переполнения буфера (в данном примере в буфере всего 10 байт).
Никогда не следует пользоваться scanf ‘ом для чтения строк.
1.2 Чтение и запись файлов: FILE* , fopen , fprintf , fscanf
Есть несколько способов работы с файлами c использованием языков C и C++.
Самый распространенный связан со структурой FILE (это не класс, потому что сущность языка C). Эта структура определена в заголовочном файле стандартной библиотеки . Размер этой структуры и ее поля зависят от ОС и от версии компилятора. Поэтому никто не пользуется структурой FILE . Обычно пользуются указателем на эту структуру: FILE* . Например:
FILE *f = fopen(«file1.txt», «r»);
- не существует файла;
- у программы недостаточно прав доступа для работы с файлом;
Для дальнейшей корректной работы следует писать примерно такой код:
if (f == NULL) // файл не удалось открыть
>
else // Работа с файлом
>
Допустим, что нам удалось открыть файл, т.е. f != NULL . Тогда для того, чтобы считывать файл, можно использовать функцию:
Эта функция работает аналогично функции scanf . Поэтому использовать эту функцию небезопасно! Все проблемы, перечисленные для scanf ‘а, имеют место и при работе с fscanf ‘ом.
Если мы хотим записать в файл что-то, то мы должны сначала открыть его на запись:
FILE *f = fopen(«file2.html», «w»);
Тут «w» означает, что мы открываем файл на запись (от write). Если файл не существовал, то он создастся и откроется на запись, а если он существовал, то он сначала будет уничтожен, а затем создан заново, и потом файл будет открыт на запись.
Еще один способ открыть файл — это открыть его на дозапись. Это можно сделать с помощью параметра «a» (от append). Если файл не существовал, то он создастся и откроется на запись, а если он существовал, то он откроется на запись, и запись будет производится в конец файла.
Затем можно использовать функцию fprintf(f, . )
1.2.1 Зачем нужно закрывать файлы
- Зададимся вопросом: «Что надо сделать после того, как мы поработали с файлом?»
Формальный ответ: «Закрыть файл.» Это можно сделать с помощью функции:
fclose(f);
Но зачем это делать?
Ввиду механического устройства жесткого диска, данные в файл попадают не сразу. Сначала данные записываются в так называемый буфер (область оперативной памяти), и когда он переполнится, то данные из буфера будут записаны в файл. Такая схема придумана для ускорения работы с файлами. На самом деле, буфер — это поле структуры FILE : указатель на массив char ‘ов.
1.2.2 Важность буфера при работе с файлами
- Рассмотрим следующую ситуацию. Программа пишет протокол своих действий в файл (например, с помощью функции fprintf ). Допустим, что программа сломалась. Понятно, что скорее всего получится так, что в файл последний fprintf (последний протокол действий) не запишется. Причина тому — это буфер.
Чтобы «протолкнуть» буфер в файл, используется функция
В коде это выглядит примерно так:
1.3 Стандартные уже открытые файлы: stdin, stdout, stderr
С точки зрения UNIX клавиатура и экран — это файлы.
Есть три стандартные константы:
FILE *stdin
FILE *stdout
FILE *stderr
Это три стандартных заранее открытых файла.
stdin — это стандартный файл (поток) ввода, а stdout — стандартный файл (поток) вывода. Таким образом:
scanf(. ) в точности эквивалентно fscanf(stdin, . )
printf(. ) в точности эквивалентно fprintf(stdout, . )
Такой гибкостью можно воспользоваться при написании программы для работы с файлами. Например, для отладки программы можно выводить информацию на экран монитора, а не в файл. Для этого в начале работы с файлом пишем две строчки:
//FILE *f = fopen(. );
FILE *f = stdin;
При этом код программы будет содержать такие функции: fscanf(f, . ) или fprintf(f, . ) . А когда отладка законичится, просто снимаем/ставим соответствующие комментарии в двух строчках программы.
stderr — это стандартный файл (поток) ошибок. По умолчанию выводит данные на экран.
Но существует заметное отличие этого «файла» от stdin и stdout : stderr — небуферизованный файл (поток). Поэтому в этот файл (поток) все байты уходят без «задержки», которая могла бы возникнуть при буферизированном подходе. Понятно, что польза от этого подхода заключается в том, что вместо кода:
1.4 Текстовые и бинарные файлы; что меняет опция t/b
fopen(f, «file1.txt», «w»);
Почему второй параметр «w» является строкой, а не символом?
На самом деле бывает много способов прочитать/записать файл. Например:
fopen(«file1.txt», «wt») — откроет файл как текстовый файл;
fopen(«file1.txt», «wb») — откроет файл как бинарный файл.
Но в чем отличие?
Разница заключается лишь в том, что символы переноса строк запишутся по разному.
Рассмотрим пример в UNIX и Windows:
Исходная строка кода выглядит так: fprintf(«Hello\n»);
-
Откроем в Windows файл на запись с параметром «wb» (как бинарный файл). Это означает, что в него запишется в точности то, что мы передали в функции fprintf . Тогда в файл запишутся ровно 6 байт: Hello\10
1.5 Как же читать/писать на самом деле: fgets , fread и fwrite
Использование функций ptintf и scanf для записи и для чтения — это очень плохая идея. Тогда все-таки как лучше читать и записывать?
Хороший способ чтения из файла дает функция fgets() (от «get string»):
char *fgets(char *buffer, size_t length, FILE *file);
- buffer — это указатель на буфер, в который мы читаем;
- length — это размер буфера;
- file — это файл, из которого мы читаем (если читаем с клавиатуры, то разумно использовать stdin ).
- Функция возвращает строку
Налицо быстрота и безопасность. Главное отличие от scanf ‘а заключается в том, что функция перестанет читать в тот момент, когда закончится буфер. Быстрота обусловлена тем, что функция scanf должна в момент выполнения разобрать форматную строку, в то время как fgets просто читает строку.
1.5.1 Как доставать числа? Семейство atoi, sscanf
В то время как фунция fgets читеат обычную строку, функция scanf может читать и различные другие типы (целые, вещественные числа).
В языке C есть семейство функций ~ atoi (a — ASCII , i — integer ):
Функция принимает единственный параметр строку и пытается ее привести в типу int . Надо заметить, что функция atoi безопасная, но не очень удобная. Безопасная в том смысле, что не сломается: atoi(«25a») == 25 . «Неудобства» заключаются в том, то если мы передаем в качестве параметра строку, в которой есть не только числа, нужно быть очень внимательным и знать, как работает эта функция. Функция atoi никак не проинформирует нас, если преобразование прошло неудачно.
Например, atoi(«abc») == 0 , что на самом деле не совсем соостветствует действительности. Использовать функцию atoi нужно лишь в том случае, когда вы уверены, что в строке есть число.
Родственные функции: atol, atoll, atof, strtol .
Им соответствуют функции для преобразования в типы long , long long и float .
Рассмотрим подробнее strtol :
long strtol(char *buffer, char **endPtr, int base);
- buffer — это указатель на буфер, из которого мы читаем;
- endPtr — это переменная, которая используется для того, чтобы сообщить нам насколько успешно произошло преобразование;
это указатель на char * , в котором записан первый символ, который не смог проинтерпретироваться с помощью функции strtol ;
Применение выглядит примерно так:
char *end;
char *ptr = «25a»;
int N = strtol(ptr, &end, 10);
Теперь end указывает на «a».
if (ptr == end) <
// ничего не получилось прочитать
>
Более мощное средство
Есть более мощное средство, чем нежели fgets + atoi . Речь идет о функции sscanf .
Вместо использования функции fscanf(f, «%d», &N) можно использовать связку:
fgets(ptr, 100, f);
sscanf(ptr, «%d», &N);
В чем преимущество и мощность такого подхода?
- Мы знаем длину того, что мы прочитали;
- Рассмотрим следующую ситуацию: мы хотим прочитать какие-то данные, но не смогли из-за ошибки.
Используя такой подход, мы можем передать пользователю сообщение об ошибке и ту строчку, которую нам не удалось прочитать: ptr . С использованием fscanf ‘а это невозможно.
1.5.2 fread и fwrite
На самом деле не все файлы выглядят как текст. Файле могут быть записаны числовые данные.
size_t fread(void *ptr, size_t size, size_t nelts, FILE *f);
- void *ptr — указатель на ту область памяти, в которую мы читаем;
- size_t size — размер элемента, который мы читаем;
- size_t nelts — максимальное количество элементов, которые можно записать;
- FILE *f — файл, из которого читаем;
- size_t fread() — сама функция возвращает количество элементов, которые удалось прочитать.
size_t fwrite(const void *ptr, size_t size, size_t nelts, FILE *F);
Аналогично fread эта функция возвращает количество элементов, которые удалось записать.
Тут параметр nelts просто показывает, сколько элементов надо вывести.
1.6 Другие полезные опции: fseek и ftell
Для файлов, которые открыты на чтение есть полезные функции. Одна из них это:
int fseek(FILE *f, long offset, int flag);
- FILE *f — файл, в котором передвигаемся;
- long offset — количество байтов для отступа, отступ производится в соответствии с 3-м параметром;
- int flag — позиция, от которой будет совершен отступ; в стандартной библиотеке C для этого параметра определены 3 константы:
SEEK_SET — начало файла;
SEEK_CUR — текущас позиция;
SEEK_END — конец файла;
long int ftell(FILE *f);
2 Другие подходы для работы с файлами
2.1 File descriptors. Open, close, read, write
В языке C есть много способов работы с файлами. Помимо структуры FILE можно использовать так называемые дескрипторы файла (file descriptors). Дескриптор файла — целое неотрицательное число. Оно обозначает номер открытого файла в таблице открытых файлов операционной системы. Использование дескрипторов файла — более низкий уровень, чем нежели ипользование струкруты FILE. Структура FILE — сущность языка C и его стандартной библиотеки, тогда как дескриптор файла — сущность операционной системы. Например, при работе со структурой FILE автоматически создается буфер, и программист работает с более высокоуровневой абстракцией. А при работе с дескрипторами файла программист должен позаботится о буферизации вручную.
Пример работы с дескрипторами файла довольно прост и почти в точности повторяет процесс работы со структурой FILE:
Сходство работы с дескрипторами файла с работой со структурой FILE заключается в том, что в названии функций отсутствует буква «f» . Иногда параметры функций незначительно отличаются.
Структуру FILE полезно использовать при работе с настоящими «файлами» (которые находятся на жестком диске). Ипользовать дескрипторы файла полезно в случаях работы со специальными «файлами». В этом подходе есть своя специфика работы, но сейчас просто полезно знать, что такой подход существует.
Аналогами stdin, stdout и stderr в дескрипторах файла являются числа 0, 1 и 2 соответственно. Стандарт POSIX.1 обозначил числа 0, 1, 2 символическими константами STDIN_FILENO, STDOUT_FILENO и STDERR_FILENO соответственно.
2.2 Memory mapping. Что делает mmap
Следующий способ работы с файлами удобен в тех случаях, когда приходится читать файл нелинейно: надо «ходить» вперед и назад. В предыдущих подходах такие ситуации оказывались неудобными с точки зрения программирования: получился бы громоздкий код.
В языке C был придуман удобный способ работы в таких ситуациях, который называется memory mapping. Соответствующая функция:
Работает эта функция примерно так. Мы указываем этой функции файл на диске, и она «отображает» этот файл в такую-то область в памяти. В результате работы функции мы получаем указатель на начало файла. И потом мы можем работать с этим файлом как с обычным указателем на какую-то область памяти: можем «ходить» вперед и назад по этому файлу.
Можно «отобразить» не весь файл целиком, а, например, отдельную часть файла: с 3-его килобайта по 4-ый килобайт.
2.3 Win32 API: FileCreate, FileRead , etc.
При работе с файлами в ОС Windows можно использовать все те функции, которые были описаны выше. В ОС Windows есть своя большая стандартная библиотека Win32 API . В этой библиотеке также есть функции для работы с файлами: например, функции FileCreate(. ) или FileOpen(. ) . Они по своей работе похожи на функции из стандартной библиотеки C, но отличия также присутствуют. Они заключаются в параметрах этих функций и небольших «хитростях», которые мы здесь опустим.
Если вы программируете под ОС Windows и пишите программу для работы в ОС Windows, то стоит пользоваться библиотекой Win32 API для работы с файлами.
3 Ввод и вывод в языке C++, потоки
В языке C++ объекты для работы с файлами называются потоками (streams). В данном случае слово «поток» означает то же самое, что и «файл» в языке C.
Классы для работы с файлами в языке C++ называются std::istream и std::ostream для ввода и вывода соответственно.
3.1 Глобальные переменные std::cout, std::cin, std::cerr
В header’е
В этом классе есть перегруженный оператор
В данном случае на экран будет выведена единица.
Еще в header’е объявлены переменные std::cin и std::cerr для стандартного потока ввода и потока ошибок соответственно. Они являются объектами классов std::istream и std::ostream соотсветственно.
Аналогично тому, как stderr отличается от stdin , в языке C++ std::cerr отличается от std::cout отсутствием буферизации.
В классе std::istream есть перегруженный оператор >>. Можно считывать информацию из стандартного потока ввода (с клавиатуры).
3.2 Форматированный вывод возможен: std::ios::hex
Возможен ли форматированный вывод, которым мы пользовались в языке C фунцией printf() ? Наример, как вывести ту же переменную N в 16-ой записи?
В языке C++ форматированный вывод возможен при помощи вывода на экран специальной управляющей команды:
В точности то же самое выведет команда printf(«%x», N);
Чтобы не писать перед кажой переменной ее формат, можно использовать функцию:
Она установит формат вывода в стандартный поток вывода на экран. Этот подход настолько же мощный, как и использование форматной печати с помощью printf .
3.3 Операторы >
- &os — поток, в который мы будем выводить;
- N — переменная, которую мы будем выводить;
- Оператор возвращает ссылку на поток, в результате чего можно писать так: std::cout
В случае оператора >> все аналогично.
Если у нас есть класс комплексных чисел Complex , то вывод этих чисел через оператор
3.4 Работа с файлами
Классами для работы с файлами в языке C++ являются ifstream, ofstream и fstream .
Код для открытия файла и его чтения выглядит примерно так:
ifstream ifs;
ifs.open(«file1.txt»);
// далее с помощью оператора >> можно читать из файла, если он успешно открылся;
Аналогично можно использовать конструктор с параметром: ifs(«file1.txt»); после чего создается объект и открывается по возможности файл.
В классе istream есть метод close() , который закрывает файл (на подобие работы с файлами в языке C). Однако вызывать этот метод необязательно. Дело в том, что в деструкторе класса этот метод вызовется автоматически.
Работа с объектами классов ofstream и ofstream и fstream осуществляется по аналогичному сценарию.
3.5 Класс stringstream
Класс stringstream наследуется от iostream .
Используется этот для класс для следующих целей. Если мы хотим выводить комплексные числа не только на экран или в файл, но и в окно какой-нибудь программы (GUI), то как использовать stringstream ? При этом мы не хотим писать один и тот же код программы.
Можно просто печатать в строку с помощью stringstream .
3.6 Иерархия классов
4 Общий совет
Общий совет заключается в том, что не надо смешивать техники для работы с файлами.
Например, не надо в одной и той же программе использовать функции из стандартной библиотеки C ( fread / fwrite ) и классы-потоки из языка C++ ( istream / ostream ).
Использование Visual C# для выполнения простого операций ввода-вывода файлов
В этой статье описывается выполнение базового операций ввода-вывода файлов в Visual C#, а также приведен пример кода, демонстрирующий выполнение этой задачи.
Исходная версия продукта: Visual C #
Оригинальный номер базы знаний: 304430
Аннотация
- Версию Visual Basic .NET этой статьи см. в статье Как выполнить базовый файловый ввод-вывод в Visual Basic 2005 или в Visual Basic .NET.
- Сведения о версии .NET для Visual C++ этой статьи см. в статье Как выполнять базовый файловый ввод-вывод в Visual C++ или в Visual C++ .NET.
- В этой статье рассматриваются пространства System.IO имен библиотеки классов Microsoft платформа .NET Framework и System.Collections .
В этой пошаговой статье показано, как выполнить шесть основных операций ввода-вывода файлов в Visual C#. Если вы не знакомы с платформа .NET Framework, вы увидите, что объектная модель для операций с файлами в .NET похожа на FileSystemObject модель (FSO), которая пользуется популярностью у многих разработчиков Visual Studio 6.0. Чтобы упростить переход, функциональность, показанная в статье Использование FileSystemObject с Visual Basic.
Вы по-прежнему FileSystemObject можете использовать в .NET. FileSystemObject Так как является компонентом COM, для .NET требуется, чтобы доступ к объекту проходил через слой взаимодействия. Microsoft .NET создает оболочку для компонента, если вы хотите его использовать. File Однако классы , FileInfo , Directory , DirectoryInfo и другие связанные классы в платформа .NET Framework предоставляют функциональные возможности, недоступные при FSO, без накладных расходов на уровень взаимодействия.
Демонстрация операций ввода-вывода файлов
В примерах в этой статье описываются основные операции ввода-вывода файлов. В разделе Пошаговый пример описывается создание примера программы, демонстрирующей следующие операции ввода-вывода файлов:
- Чтение текстового файла
- Запись текстового файла
- Просмотр сведений о файлах
- Вывод списка дисков
- Список папок
- Вывод списка файлов
Если вы хотите использовать следующие примеры кода напрямую, имейте в виду следующее:
-
System.IO Включите пространство имен следующим образом:
using System.IO;
string winDir=System.Environment.GetEnvironmentVariable("windir");
private void addListItem(string value)
Вместо объявления и использования addListItem функции можно напрямую использовать следующую инструкцию:
this.listBox1.Items.Add(value);
Чтение текстового файла
В следующем примере кода для чтения файлаSystem.ini используется StreamReader класс . Содержимое файла добавляется в элемент управления ListBox. Блок try. catch используется для оповещения программы, если файл пуст. Существует множество способов определить, когда достигается конец файла. В этом примере метод используется Peek для изучения следующей строки перед ее чтением.
StreamReader reader=new StreamReader(winDir + "\\system.ini"); try < do < addListItem(reader.ReadLine()); >while(reader.Peek()!= -1); > catch < addListItem("File is empty"); >finally
Запись текстового файла
Этот пример кода использует класс для StreamWriter создания и записи в файл. Если у вас есть существующий файл, его можно открыть таким же образом.
StreamWriter writer = new StreamWriter("c:\\KBTest.txt"); writer.WriteLine("File created using StreamWriter class."); writer.Close(); this.listbox1.Items.Clear(); addListItem("File Written to C:\\KBTest.txt");
Просмотр сведений о файлах
Этот пример кода использует FileInfo объект для доступа к свойствам файла. в этом примере используется Notepad.exe. Свойства отображаются в элементе управления ListBox.
FileInfo FileProps =new FileInfo(winDir + "\\notepad.exe"); addListItem("File Name = " + FileProps.FullName); addListItem("Creation Time = " + FileProps.CreationTime); addListItem("Last Access Time = " + FileProps.LastAccessTime); addListItem("Last Write TIme = " + FileProps.LastWriteTime); addListItem("Size = " + FileProps.Length); FileProps = null;
Вывод списка дисков
В этом примере кода классы и Drive используются Directory для вывода списка логических дисков в системе. В этом примере результаты отображаются в элементе управления ListBox.
string[] drives = Directory.GetLogicalDrives(); foreach(string drive in drives)
Вывод списка вложенных папок
В этом примере кода метод класса используется GetDirectories Directory для получения списка папок.
string[] dirs = Directory.GetDirectories(winDir); foreach(string dir in dirs)
Вывод списка файлов
В этом примере кода используется GetFiles метод класса для Directory получения списка файлов.
string[] files= Directory.GetFiles(winDir); foreach (string i in files)
Многие вещи могут пойти не так, когда пользователь получает доступ к файлам. Файлы могут не существовать, файлы могут использоваться или пользователи могут не иметь прав на файлы или папки, к которым они пытаются получить доступ. Важно учитывать эти возможности при написании кода и обработке исключений, которые могут быть созданы.
Пошаговый пример
- В Visual C# создайте новое приложение Windows Forms. По умолчанию создается Form1 .
- Откройте окно кода для Form1 (Form1.cs).
- Удалите весь код в Файле Form1.cs.
- Вставьте следующий код в окно редактора кода программной части .
using System.Windows.Forms; using System.IO; namespace fso_cs < public partial class Form1 : Form < string winDir = System.Environment.GetEnvironmentVariable("windir"); public Form1() < InitializeComponent(); >private void button1_Click(object sender, System.EventArgs e) < //How to read a text file. //try. catch is to deal with a 0 byte file. this.listBox1.Items.Clear(); StreamReader reader = new StreamReader(winDir + "\\system.ini"); try < do < addListItem(reader.ReadLine()); >while (reader.Peek()!= -1); > catch < addListItem("File is empty"); >finally < reader.Close(); >> private void button2_Click(object sender, System.EventArgs e) < //Demonstrates how to create and write to a text file. StreamWriter writer = new StreamWriter("c:\\KBTest.txt"); writer.WriteLine("File created using StreamWriter class."); writer.Close(); this.listBox1.Items.Clear(); addListItem("File Written to C:\\KBTest.txt"); >private void button3_Click(object sender, System.EventArgs e) < //How to retrieve file properties (example uses Notepad.exe). this.listBox1.Items.Clear(); FileInfo FileProps = new FileInfo(winDir + "\\notepad.exe"); addListItem("File Name = " + FileProps.FullName); addListItem("Creation Time = " + FileProps.CreationTime); addListItem("Last Access Time = " + FileProps.LastAccessTime); addListItem("Last Write TIme = " + FileProps.LastWriteTime); addListItem("Size = " + FileProps.Length); FileProps = null; >private void button4_Click(object sender, System.EventArgs e) < //Demonstrates how to obtain a list of disk drives. this.listBox1.Items.Clear(); string[] drives = Directory.GetLogicalDrives(); foreach (string drive in drives) < addListItem(drive); >> private void button5_Click(object sender, System.EventArgs e) < //How to get a list of folders (example uses Windows folder). this.listBox1.Items.Clear(); string[] dirs = Directory.GetDirectories(winDir); foreach (string dir in dirs) < addListItem(dir); >> private void button6_Click(object sender, System.EventArgs e) < //How to obtain list of files (example uses Windows folder). this.listBox1.Items.Clear(); string[] files = Directory.GetFiles(winDir); foreach (string i in files) < addListItem(i); >> private void Form1_Load(object sender, System.EventArgs e) < this.button1.Text = "Read Text File"; this.button2.Text = "Write Text File"; this.button3.Text = "View File Information"; this.button4.Text = "List Drives"; this.button5.Text = "List Subfolders"; this.button6.Text = "List Files"; >private void addListItem(string value) < this.listBox1.Items.Add(value); >> >
namespace fso_cs < partial class Form1 < /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) < if (disposing && (components != null)) < components.Dispose(); >base.Dispose(disposing); > #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() < this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.button4 = new System.Windows.Forms.Button(); this.button5 = new System.Windows.Forms.Button(); this.button6 = new System.Windows.Forms.Button(); this.listBox1 = new System.Windows.Forms.ListBox(); this.SuspendLayout(); // button1 this.button1.Location = new System.Drawing.Point(53, 30); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(112, 23); this.button1.TabIndex = 1; this.button1.Text = "button1"; this.button1.Click += new System.EventHandler(this.button1_Click); // button2 this.button2.Location = new System.Drawing.Point(53, 62); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(112, 23); this.button2.TabIndex = 2; this.button2.Text = "button2"; this.button2.Click += new System.EventHandler(this.button2_Click); // button3 this.button3.Location = new System.Drawing.Point(53, 94); this.button3.Name = "button3"; this.button3.Size = new System.Drawing.Size(112, 23); this.button3.TabIndex = 3; this.button3.Text = "button3"; this.button3.Click += new System.EventHandler(this.button3_Click); // button4 this.button4.Location = new System.Drawing.Point(53, 126); this.button4.Name = "button4"; this.button4.Size = new System.Drawing.Size(112, 23); this.button4.TabIndex = 4; this.button4.Text = "button4"; this.button4.Click += new System.EventHandler(this.button4_Click); // button5 this.button5.Location = new System.Drawing.Point(53, 158); this.button5.Name = "button5"; this.button5.Size = new System.Drawing.Size(112, 23); this.button5.TabIndex = 5; this.button5.Text = "button5"; this.button5.Click += new System.EventHandler(this.button5_Click); // button6 this.button6.Location = new System.Drawing.Point(53, 190); this.button6.Name = "button6"; this.button6.Size = new System.Drawing.Size(112, 23); this.button6.TabIndex = 6; this.button6.Text = "button6"; this.button6.Click += new System.EventHandler(this.button6_Click); // listBox1 this.listBox1.FormattingEnabled = true; this.listBox1.Location = new System.Drawing.Point(204, 30); this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(270, 199); this.listBox1.TabIndex = 7; // Form1 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(525, 273); this.Controls.Add(this.button6); this.Controls.Add(this.button5); this.Controls.Add(this.button4); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Controls.Add(this.listBox1); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); >#endregion private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button3; private System.Windows.Forms.Button button4; private System.Windows.Forms.Button button5; private System.Windows.Forms.Button button6; private System.Windows.Forms.ListBox listBox1; > >
Обратная связь
Были ли сведения на этой странице полезными?