Как завершить потоковый ввод python


Скачай курс
в приложении
Перейти в приложение
Открыть мобильную версию сайта
© 2013 — 2023. Stepik
Наши условия использования и конфиденциальности

Public user contributions licensed under cc-wiki license with attribution required
Работа с потоками ввода-вывода в C++
Программа, выводящая в консоль сообщение Hello, world! , с которой традиционно начинают изучение языка программирования, на языке C++ выглядит следующим образом:
#include using namespace std; int main() cout <"Hello, world!" <endl; return 0; >
Директива #include и функция main() знакомы читателю по языку C. Способ вывода строки в консоль отличается от стандартной функции printf языка C и даёт нам повод начать разговор про C++.
Чтобы считать данные из стандартного потока ввода stdin , необходимо воспользоваться объектом cin и оператором извлечения >> .
int a; double x; cin >> a >> x;
Здесь мы снова построили цепочку вызовов и получили значения сразу для двух переменных. При обращении к потоку ввода мы не указывали тип данных, которые необходимо прочитать. Оператор >> сам определяет типы объектов и заполняет их из потока ввода.
Объекты cout , cin , а также операторы вставки и извлечения определены в заголовочном файле
Работа с файлами
Все операции ввода-вывода в C++ организованы через потоки и операторы > . Мы уже рассмотрели операции ввода-вывода в потоки stdout и stdin . Операции ввода-вывода с файлами устроены схожим образом. Для работы с файловыми потоками необходимо подключить заголовочный файл . Следующая программа создает файл test.txt и записывает в него строку Hello, world!
#include using namespace std; int main() ofstream ofile("test.txt", ios::out); if (ofile.is_open()) ofile <"Hello, world!"; > return 0; >
Сначала мы создали объект типа ofstream . В его конструктор мы передали имя файла test.txt и флаг ios::out , указывающий на то, что мы собираемся осуществлять операции вывода. Всегда необходимо проверять, что операция открытия/создания файла прошла успешно. Если не выполнить эту проверку, то, если по какой-либо причине файл открыть не удалось, дальнейшие шаги приведут к аварийному завершению программы. Метод is_open() позволяет выполнить такою проверку. Дальше идет уже знакомый нам вызов оператора
Чтение данных из файла производится следующим образом:
#include #include #include using namespace std; int main() ifstream ifile("test.txt", ios::in); if (ifile.is_open()) string line; while (ifile >> line) cout <line <' '; > > return 0; >
Здесь мы воспользовались файловым потоком ввода ifstream и флагом ios::in . В этой программе мы создали переменную line типа string , чтобы хранить считанные из файла данные. Неочевидным моментом здесь является использование цикла while . Дело в том, что оператор >> считывает символы до тех пор, пока не встретит разделитель (пробел, табуляция или перенос строки). Если бы мы вызвали этот оператор один раз, то в переменную line было бы записано Hello, , а это не то, чего мы хотели. Цикл позволяет прочитать файл до конца.
Если же мы хотим прочитать только одну строчку из файла, то можно воспользоваться функцией getline , определенной в . С этой функцией наша программа примет следующий вид:
#include #include #include using namespace std; int main() ifstream ifile("test.txt", ios::in); if (ifile.is_open()) string line; getline(ifile, line); cout <line <end; > return 0; >
Наконец, для чтения символов из потока по одному можно использовать метод get()
char c; while (ifile.get(c)) cout <c; >
Аналогичный метод есть и у объекта cin .
По умолчанию файловые потоки работают в текстовом режиме, т.е. передают и принимают строковые символы. В некоторых случаях необходимо работать непосредственно с последовательностью байт, которые не должны быть интерпретированы как строковые символы. Для таких случаев существует флаг ios::binary . Детали работы с бинарными файлами смотрите в документации.
Строковые потоки
Часто бывает удобно работать со строковыми потоками. Инструменты для работы со строковыми потоками подключаются с помощью заголовочного файла . Строковые потоки позволяют удобно инициализировать объекты различных типов из их текстового представления. Представим себе, что мы получили географические координаты НГУ в виде строки «(54.847830, 83.094392)» . Наша задача извлечь из строки две величины типа double . Сделать это можно следующим образом:
#include #include #include using namespace std; int main() string nsucoor("(54.847830, 83.094392)"); stringstream ss(nsucoor); double lat, lon; ss.ignore(1); // skip '(' ss >> lat; ss.ignore(2); // skip ", " ss >> lon; cout <lat <", " <lon <endl; return 0; >
Резюме
Мы обсудили, что все операции ввода-вывода в С++ реализованы единообразно с помощью потоков. Вывод в поток осуществляется с помощью оператора вставки > . Мы рассмотрели три типа потоков: стандартные, файловые и строковые. Этого достаточно для уверенного начала работы с потоками ввода-вывода в C++.
Документация
- http://www.cplusplus.com/reference/iolibrary/
- https://en.cppreference.com/w/cpp/io
Python: потоковый ввод stdin
В общем (классическом) виде чтение с помощью stdin производится следующим образом:
import sys for line in sys.stdin: # rstrip('\n') "отрезает" от строки line идущий справа символ # перевода строки, ведь print сам переводит строку print(line.rstrip('\n'))
Если запустить эту программу, она будет работать вечно. Чтобы показать, что ввод закончен, пользователю недостаточно нажать Enter — компьютер не знает, завершил пользователь работу или будет еще что-то вводить (при этом Enter превратится в пустую строку). Вместо этого надо нажать Ctrl + D (если работаете в консоли Linux или IDE PyCharm) либо Ctrl + Z, затем Enter (если работаете в консоли Windows).
Если вы работаете в IDE Wing, кликните правой кнопкой мыши и выберите Send EOF, затем нажмите Enter. Это запишет в поток ввода специальный символ EOF (end of file), который отмечает конец ввода.
Через sys.stdin можно вычитать всё, что попадает через ввод в список (количество строк ввода заранее неизвестно):
data = list(map(str.strip, sys.stdin))
Все строки можно считать (с сохранением символов перевода строки) в список вот таким образом:
data = sys.stdin.readlines()
Cчитать многострочный текст из стандартного потока ввода в текстовую переменную можно вот так:
str_data = sys.stdin.read()
Как завершить потоковый ввод python
При запуске программы на Си автоматически открываются ряд потоков, основными из которых являются следующие:
- Стандартный поток ввода stdin
- Стандартный поток вывода stdout
- Стандартный поток вывода сообщений об ошибках stderr
Стандартный поток ввода stdin по умолчанию соответствует клавиатуре, а потоки stdout и stderr — экрану монитора.
Для управления вводом-выводом с помощью этих потоков используются ряд функций:
- getchar() : ввод с клавиатуры одного символа
- putchar() : вывод на консоль одного символа
- fgets() : ввод одной строки
- puts() / fputs() : вывод одной строки на консоль
- scanf() : ввод с консоли с форматированием данных
- sscanf() : ввод с из строки с форматированием данных
- printf() : вывод с форматированием данных
Функции printf и scanf уже рассматривались ранее, поэтому посмотрим, как применять остальные функции.
Ввод и вывод символов
Для ввода и вывода символа применяются функции getchar() и putchar() . Но следует сказать, что на самом деле они полноценными функциями не являются, а определены как макросы в заголовочном файле stdio.h :
#define getchar() getc(stdin) #define putchar(c) putc((c), stdout)
Вывод символа
Для вывода отдельного символа на консоль предназначена функция putchar() со следующим прототипом:
int putchar(int c);
Выводимый символ в виде числового кода передается в putchar в качестве параметра, он же возвращается функцией.
#include int main(void) < char c = 'A'; putchar(c); // Выводим символ A >
Ввод символа
Для ввода одного символа с клавиатуры применяется функция getchar() , которая имеет следующий прототип:
int getchar(void);
В качестве результата функция возвращает числовой код введенного символа.
При использовании функции getchar следует учитывать, что при печати текста посредством клавиатуры в буфер операционной системы заносятся коды печатаемых символов, а сами символы отображаются на экране. Поучение программой введенного символа из буфера производится с помощью нажатия клавиши Enter.
И если буфер операционной системы не пуст, то при вызове функции getc() она получает очередной символ из буфера. Если же буфер пуст, то происходит чтение байта из потока ввода с помощью системной функции, название которой зависит от операционной системы.
При этом при нажатии клавиши Enter, в буфер также помещается код этой клавиши. То есть если мы введем один символ и нажмем на Enter, в буфере окажутся два числовых кода — введенного символа и клавиши Enter. И это надо учитывать при работе с функцией getchar. В частости, рассмотрим простой, но показательный пример:
#include int main(void) < printf("1"); getchar(); // ожидание ввода символа printf("2"); getchar(); // ожидание ввода символа printf("3"); return 0; >
Сначала на экран выводится цифра 1, после чего функция getchar ожидает ввода символа. Если после ввода символа мы нажмем Enter, то в буфер будет помещены два числовых кода — введеного символа и клавиши Enter. Поэтому при втором вызове getchar эта функция считывает байт из буфера — то есть числовой код клавиши Enter.
Например, введем при первом вызове функции getchar символ «a», а затем Enter:
1a 23
Но если при каждом вызове getchar мы будем только нажимать клавишу Enter, тогда в буфер будет заноситься только код этой клавиши, и соответственно программа будет работать, как и ожидалось:
1 2 3
Применим функции getchar и putchar для ввода и вывода символов с клавиатуры:
#include int main(void) < int c; while((c=getchar())!=EOF) < putchar(c); >return 0; >
Функция getchar() считывает числовой код символа, который потом выводится в функции putchar() . Для вывода из программы необходимо ввести комбинацию клавиш Ctrl+C.
Ввод и вывод строк
Вывод строк и puts
Для вывода одной строки на консоль предназначена функция puts() со следующим прототипом:
int putchar(char *s);
В качестве параметра передается указатель на строку, а возвращаемым результатом функции является последний выведенный символ.
При этом функция puts() будет выводить символы переданной строки, пока не дойдет до нулевого символа ‘\0’. Если же выводимый массив символов не содержит этого символа, то результат программы неопределен. Например:
#include int main(void) < puts("Hello World"); // выводим строковый литерал char* name = "Hello Metanit.com"; puts(name); // выводим значение переменной return 0; >
Hello World Hello Metanit.com
Вывод строк и fputs
Функция fputs() также записывает в поток вывода строку, то есть набор символов, который завершается символом ‘\0’. При записи строки нулевой символ ‘\0’ не записывается. Она имеет следующий прототип:
int fputs(const char *s, FILE *stream);
Первый параметр функции — записываемая строка, а второй — указатель на поток вывода. В качестве результата функция возвращает неотрицательное целое число. При ошибках в процессе записи возвращается значение EOF .
Применим функцию для записи в стандартный поток вывода, то есть на консоль. В этом случае в качестве второго параметра надо передать значение stdout :
#include int main(void)
Ввод строк и fgets
Для ввода строки с клавиатуры применяется функция fgets() , которая имеет следующий прототип:
char *fgets(char *str, int count, FILE *stream);
- char *str : строка, в которую производится считывание.
- int count : сколько символов необходимо считывать.
- FILE *stream : файловый поток, из которого производится считывание. В качестве потока ввода может выступать и консольный ввод.
Функция fgets() прекращает считывание, когда пользователь нажимает клавишу ENTER, то есть когда в поток добавляется символ перевода строки.
Рассмотрим считывание строки с консоли. Для этого в качестве третьего параметра в функцию передается значение stdin :
#include #define MAX 15 int main(void)
Здесь функция fgets считывает не более 15 символов в строку name, а В реальности функция предложит ввести 14 символов, так как последний символ зарезервирован для нулевого символа ‘\0’. Если будет введено больше символов, то fgets все равно считает не более 15 символов. Таким образом функция позволяет проверить количество считываемых символов и поэтому считается безопасной.
Пример работы программы:
Enter name: Tom Smith Your name: Tom Smith
Стоит отметить, что функция fgets() возвращает указатель char * — указатель на буфер, в который считаны данные. В реальности это тот же самый буфер, который передавался в качестве первого параметра, то есть в примере выше — это массив name. Однако этот результат может нам пригодится для проверки успешности выполнения функции — если считывание прошло неудачно, то функция возвращает NULL :
#include #define MAX 15 int main(void) < char name[MAX]; printf("Enter name: "); if(fgets(name, MAX, stdin) != NULL) // if(fgets(name, MAX, stdin)) - можно сократить < printf("Your name: %s\n", name); >else < printf("Critical Error. "); >return 0; >
Для эмуляции ошибки можно передать в функцию вторым параметром число 0.
fgets и scanf
При использовании функции fgets() после функции scanf() мы можем столкнуться с некорректным вводом:
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
В данном случае сначала с помощью функции scanf() считываем число в переменную age. После этого считываем имя — строку с помощью функции fgets() в переменную name. Но посмотрим, какой будет результат работы программы:
Input age: 39 Input name: Age: 39Name:
В данном случае мы видим, что ввод имени с помощью fgets вроде как пропускается. По крайней мере мы не можем ввести имя, а программа сразу же выводит результат.
Все дело в том, что функция scanf() считывает именно то, что ей предписано — число в виде переменной типа int. Все остальные символы остаются в буфере, в который предварительно попадают введенные с клавиатуры символы. Так, после ввода возраста мы нажимаем на клавишу Enter, и в буфер попадает символ «\n», то есть перевод строки. И fgets считывает этот символ из буфера, после чего ввод имени завершается. Очевидно, это не то поведение, на которое мы рассчитывали.
Чтобы исправить ситуацию, мы можем использовать различные хаки. Рассмотрим пару из них. Все они сводятся к тому, чтобы вынуть из буфера этот символ перевода строки.
Первый способ — считывание символа с помощью вызова scanf(«%*c») :
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); scanf("%*c"); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
Второй способ — мы можем считать символ с помощью getchar() :
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); getchar(); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
Результат работы программы:
Input age: 39 Input name: Tom Age: 39 Name: Tom
