Console writeline c что это
Доброго времени суток! В этом уроке мы поговорим о том, как получать данные от пользователя, это очень важный момент для любой компьютерной программы. В принципе, приложение может получать информацию от пользователя (или внешнего мира) разными способами, например, через графический интерфейс пользователя (через различные поля ввода и т.п.), читать из файла, принимать по сети от удаленного источника, ну или как в нашем случае – получать информацию, введенную пользователем с клавиатуры.
Помните, что получение информации от пользователя крайне важный момент, так как большинство ошибок в программах возникают из-за некорректных входных данных, а точнее, из-за недостаточной их обработки.
И так, к делу! Вспомним пример одного из предыдущих уроков, в котором мы в цикле, запрашивали информацию у пользователя, до тех пор, пока он не введет строку «выход». Вот фрагмент исходного кода:
//Переменная для хранения введенной строки string userString = ""; //Цикл с постусловием do < //Приглашение пользователю Console.Write("Введите любую строку и нажмите клавишу Enter: "); /* * Получение веденной с клавиатуры строки, * введенная строка сохраняется в переменную userString */ userString = Console.ReadLine(); //Вывод введенной строки Console.WriteLine("Пользователь ввел строку: " + userString); >while (userString != "выход");
Получение информации с клавиатуры и сохранения этой информации в переменную заключается в одной лишь строке:
userString = Console.ReadLine();
Всё очень просто, после того как пользователь введет строку и нажмет на клавишу «Enter», информация окажется в переменной «userString». Но тут есть один нюанс, операция «Console.ReadLine();» (на самом деле, это вызов метода «ReadLine», класса «Console») возвращает как результат строку. Всё бы ничего, но на практике нам потребуется получать от пользователя не только строки, но и числа, например. Так что, нужно научиться преобразовывать строковые значения в численные. К счастью, в языке C# есть инструмент для преобразования типов. На практике, это выглядит примерно так:
//Получение строки string userString = Console.ReadLine(); //Преобразование строки в число (в тип int) int intValue = Convert.ToInt32(userString);
Для преобразования типов в C# можно использовать класс (позже я расскажу, что такое класс, а пока не забивайте себе голову этим) «Convert», у этого класса есть большое количество методов (функций – если хотите), так вот, метод «ToInt32» принимает один аргумент, в круглых скобках сразу после имени метода, в нашем случае, этот аргумент является строкой, которая и будет преобразована в число (если конечно такую строку можно будет преобразовать в число).
Теперь давайте напишем программу, которая запрашивает у пользователя сначала одно целое число, затем второе, а потом, выводит результат сложения этих чисел в консоль.
Создадим новый проект и напишем следующий код, в методе Main:
//Приглашение пользователю ввести первое число Console.Write("Введите первое число и нажмите клавишу Enter: "); //Получение первой строки string firstString = Console.ReadLine(); //Преобразование первой строки в число int firstArg = Convert.ToInt32(firstString); //Приглашение пользователю ввести второе число Console.Write("Введите второе число и нажмите клавишу Enter: "); //Получение второй строки string secondString = Console.ReadLine(); //Преобразование второй строки в число int secondArg = Convert.ToInt32(secondString); //Сложение двух переменных int result = firstArg + secondArg; //Вывод результата Console.WriteLine("Результат сложения введенных чисел: " + result.ToString()); /* * Обратите внимание на запись result.ToString(), * тут мы преобразовали число в строку, вызвав * метод ToString на переменной result! * Этой операцией мы будем пользоваться часто. */
Обратите внимание на комментарий в самом конце кода! Там рассказывается как перевести число, обратно в строку.
А теперь соберите проект и запустите программу. Затем, введите какое-нибудь целое число (только целое и обязательно число!), например, 25 и нажмите клавишу Enter. Потом введите другое число (хотя, можно и тоже самое), например, 10 и нажмите Enter. В результате вы должны увидеть результат сложения этих чисел! Выглядеть это будет примерно так:
Результат выполнения программы
На этот раз хватит информации. В следующем уроке мы поговорим как обрабатывать ошибки во время выполнения программы. Например, те, которые могут возникнуть в приведенном выше примере, если пользователь введет не число, а простой текст! Но это уже тема следующего урока…
Консольный ввод-вывод информации с примерами на C# и Windows Terminal
Консоль (Console)- характерная особенность ранних операционных систем (например, MS DOS), использующих интерфейс командной строки для интерактивного обмена информацией с пользователем. Консольные приложения используются и сейчас. По сравнению с графическим интерфейсом, интерфейс командной строки требует меньше системных ресурсов и предоставляет инструменты автоматизации для повторяющихся задач.
Наиболее яркими примерами интерфейсов командной строки (англ. Command line interface, CLI) являются: Командная оболочка Windows, PowerShell, а также Bash, доступная на всех платформах (наибольшее распространение Bash получил в Unix-системах и Mac, присутствует также в компонентах Подсистема Windows для Linux (англ. Windows Subsystem for Linux, WSL)).
В операционной системе Windows консоль называется окном командной строки, для вызова которой Вы можете пройти в меню Пуск — Командная строка. В 2019 году компания Micrsoft также представила Windows Terminal — современное консольное приложение для пользователей инструментов и оболочек командной строки, таких как Command Prompt, PowerShell и WSL.
Форма интерфейсов командной строки используется в основном для обработки сценариев команд с использованием последовательности операций чтения (для принятия данных путем ввода текстовой информации пользователем) и операций записи (в вывод консоли, для отображения результатов обратной связи).
На платформе Microsoft .Net Core такие операции в виде методов описаны в классе System.Console, предоставляющем базовую поддержку для приложений, считывающих и записывающих символы в консоль стандартных входных и выходных потоков.
Программный способ записи в вывод консоли
Для вывода информации на консоль применяются 2 ключевых метода класса Console — Console.WriteLine и Console.Write, отличие которых заключается в том, что WriteLine самостоятельно добавляет терминатор строки (разделитель строки) ко всему, что вы записали. Использование метода Write предполагает ручное разбиение строки на несколько путем добавления в запись вывода терминатора строки, где это необходимо.
Записывает указанные данные с текущим признаком конца строки в стандартный выходной поток.
Console.WriteLine(“Hello, World!”);
Console.WriteLine(“=Second Line=”);
Результатом вывода будет две строки.
Записывает текстовое представление заданного значения или значений в стандартный выходной поток без признака конца строки.
Console.Write(“Hello,”);
Console.Write(“ “);
Console.Write(“World!”);
Console.Write(Environment.NewLine);
Console.Write(“=Second Line=”);
Результат вывода этого примера идентичен.
Во втором примере для разделения строки используется в качестве терминатора свойство Environment.NewLine — это обеспечивает эффективный способ выбора комбинации символов конца строки, которая зависит от используемой вами платформы. Так, большинство Unix-систем применяет специальную комбинацию “\n” в качестве терминатора строки, тогда как Windows-системы “\r\n”.
Формирование строк
При выводе информации вы можете использовать операторы + или += , интерполяцию строк и иные методы для объединения и формирования строковых переменных.
Программный способ ввода информации с консоли
Как и запись в вывод, класс Console предоставляет различные методы для чтения ввода от пользователя.
Метод Console.ReadLine
Считывает набор символов до тех пор, пока не найдет признак окончания или новой строки, и возвращает все, что он считает, как строковое значение.
Console.WriteLine(“What is your name?”);
string response = Console.ReadLine();
Console.WriteLine(“Hello, “ + response+“!“);
Метод Console.Read
Считывает следующий символ в строке и возвращает его как код целочисленного символа.
Console.WriteLine(“Please, type anything: “);
int value = Console.Read();
Console.Write(“You typed: “ + (char)value);
В отличие от ReadLine , метод Read возвращает по одному символу за раз, пока не достигнет конца ввода. Read фактически не возвращает строку, он возвращает целое число, представление ASCII введенного символа. В примере используется функция char() для преобразования полученного целого числа, чтобы получить действительно введенный символ.
Метод Console.ReadKey
Считывает следующий символ в строке и возвращает его как экземпляр ConsoleKeyInfo.
ConsoleKeyInfo описывает нажатую клавишу, включая символ, представленный этой клавишей, и состояние управляющих клавиш-модификаторов (например, Shift, Alt и др.). Нижеследующий пример ожидает нажатия клавиши Enter.
while (Console.ReadKey().Key != ConsoleKey.Enter) <>
Быстрый консольный ввод на .NET
Во времена, когда .NET был закрытой технологией только для Windows, за ним и языком C# закрепилась репутация платформы, которая отлично подходит для решения бизнес-задач, но непригодна для соревновательного программирования и написания высокопроизводительного кода.
Часто приходится слышать, что «шарпы медленные», особенно в контексте алгоритмических задач, например с timus.online и codeforces.com. И, увы, не только слышать, но и сталкиваться с реальными проблемами, связанными с особенностями платформы, получая Wrong Answer, Runtime Error, Memory Limit, Time Limit при корректном алгоритме.
Большинство этих проблем кроется в особенностях консольного ввода и вывода. Да и часто куда проще написать cin >> n или sc.nextInt() , чем int.Parse(Console.ReadLine()) или Console.ReadLine().Split().Select(int.Parse).ToArray() , из-за чего выбор падает на другой язык.
Далее я расскажу о распространённых проблемах с консольным вводом-выводом в .NET, и о том, как сделать ввод быстрым и удобным.
Плавающая запятая
Иногда требуется считать или вывести число с плавающей точкой. Но легко забыть, что плавающие точки в .NET бывают запятыми, в зависимости от локали. Об этом особенно легко забыть, если пользоваться английской локалью в своей операционной системе.
Варианта решения два:
- задать локаль потока: Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
- передавать CultureInfo.InvariantCulture явно в такие методы, как (Try)Parse и ToString
Также в современном .NET есть параметр рантайма InvariantGlobalization , позволяющий избежать подобных проблем.
Ввод и вывод
Представим, что нам дана простая задача: нужно считать строк по 4 числа int в каждой , числа разделены пробелами. Требуется вывести сумму чисел для каждой строки.
int n = int.Parse(Console.ReadLine()); for (int i = 0; i
Может ли в этом коде что-то привести к вердикту, отличному от Accepted? Запросто.
Особенности форматирования
В условии ничего не сказано про количество пробелов, которыми разделены числа. И в итоге, если где-то пробелов больше одного, Console.ReadLine().Split() вернёт массив, содержащий пустые строки. А int.Parse упадёт с исключением, что приведёт к вердикту Runtime Error. Может показаться, что такого не бывает на контестах, но увы, случай вполне реальный.
int n = int.Parse(Console.ReadLine()); for (int i = 0; i
Неприятный нюанс, о котором надо помнить. Кстати, если раньше код обрабатывал все пробельные символы как разделители, то теперь только пробелы. Исправить можно, но будет чуть длиннее.
Проблема возникает только при построчном чтении ввода. В языках, где есть готовые способы для считывания с консоли чисел (например int n; cin >> n ), проблемы не возникает вообще.
Console Flush
Потоки ввода и вывода stdin/stdout/stderr устроены на основе буфера в памяти, в который один процесс может записать данные, а другой — прочитать. Обращаться к этому буферу ради нескольких байт — дорого, поэтому для эффективности каждый процесс может дополнительно буферизовать ввод/вывод. Продвижение данных в буфер потока происходит либо при заполнении локального, либо при вызове .Flush() .
Вызов .Flush() имеет большой смысл для интерактивных консольных приложений — пользователю нужно показать вывод в терминале сразу, а не копить его в памяти. Большинство платформ изначально адаптированы под этот сценарий и вызывают .Flush() автоматически после каждой записи.
Обратите внимание, что бывают и задачи, в которых требуется интерактивный ввод-вывод (request-response семантика). Например задачи, в которых требуется вычислить ответ, задавая «вопросы» проверяющей системе (простейший пример — программа, угадывающее слово в условном «Поле чудес», «общающаяся» с программой-ведущим)
Чтобы сэкономить на Flush, в C++ iostreams пишут:
std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
А в C# можно использовать StreamWriter для stdout вместо Console :
const int bufferSize = 16384; using var input = new StreamReader( Console.OpenStandardInput(), bufferSize: bufferSize); using var output = new StreamWriter( Console.OpenStandardOutput(), bufferSize: bufferSize); int n = int.Parse(input.ReadLine()); for (int i = 0; i
Проверим, оказывает ли .Flush() влияние на производительность замерами. Версия с Console.WriteLine отрабатывает на моём компьютере за ~490ms, а с использованием StreamWriter — за 105ms. Т.е. причина плохой производительности оказалась вовсе не в LINQ. В проверяющей системе c более медленным железом можно запросто получить Time Limit Exceed, если не учитывать автоматический .Flush() . Кстати, на заметку, в энтерпрайз приложениях проблема тоже встречается — в логировании.
Замерял на Linux, рантайм .NET 7 NativeAOT — так достигается минимальный оверхед на старте программы, порядка 1.5 ms. На Windows как минимум старт процесса был бы порядка 10 ms, даже для C++.
Для чтения также можно использовать StreamReader вместо Console . Это позволяет сэкономить на проверке, не переопределён ли Console.In при каждом чтении и использовать увеличенный буфер, но выигрыш куда менее впечатляющий — единицы миллисекунд
Обратите внимание, что задавать размер буфера консольному стриму нет смысла — параметр попросту игнорируется
Задача на ввод: аллокации
Задача 1510 с Тимуса. Для этой задачи есть два решения — за линию и с сортировкой. Её все сдают легко на том же C++, но на C# даже с умным алгоритмом из-за особенностей стандартного ввода будет Memory Limit Exceed. Почему?
В задаче установлен Memory Limit в 16 MB. Зачем? Не знаю, сохранить все числа в памяти и отсортировать он никак не мешает, ведь 500000 чисел по 4 байта — всего лишь 2 MB. Но в C# чтение ввода через Console.ReadLine приводит к аллокации строк. А строка с числом из 10 цифр, это не 4 байта, а, как минимум:
- 16 байт на заголовок объекта и указатель на Method Table
- 4 байта на хранение длины
- 20 байт на 10 символов в UTF-16
- 2 байта на null terminator для совместимости с нативным кодом, его ожидающим
Т.е. уже 42 байта на 10 символов. А 500000 раз по 42 байта — это уже 21 MB.
Но они же короткоживущие?! Читаем строку, сразу парсим, GC как-нибудь соберёт. Но срабатывание GC — не гарантированно, освобождение памяти обратно в ОС — тоже, а принудительный вызов через GC.Collect() может привести уже к Time Limit Exceed.
Как же быть? Писать ввод самостоятельно
Кастомный ввод
Дедовское решение
По C++ вспоминается решение с посимвольным чтением чисел.
Перепишем его на C# с использованием Console.Read() , а лучше — StreamReader.Read() . В этом случае использовать StreamReader оправдано, потому что обращаться к Console на каждый символ гораздо дороже, чем на каждую строку при использовании ReadLine .
После этого задача не представляет никакой сложности. На моём компьютере посимвольное чтение отрабатывает в 3 раза быстрее, чем с Console.ReadLine() .
fastscan
StreamReader reader = new StreamReader(Console.OpenStandardInput(), bufferSize: 32768); int fastscan() < bool negative = false; bool read_start = false; int number = 0; while (true) < int c = reader.Read(); if (c=='-') < negative = true; read_start = true; continue; >if (c>47 && c <58) < number = number * 10 + (c - 48); read_start = true; continue; >if (read_start) break; > if (negative) number *= -1; return number; >
Решение, однако, не идеально. Этот метод подходит для целых чисел, а сделать корректный парсинг чисел с плавающей точкой нетривиально, легко попасть на граничные случаи и ошибиться с точностью. Чтобы это понять, достаточно посмотреть Pull Request.
Тиктокерское решение
В современном .NET есть перегрузки методов Parse и TryParse принимающие ReadOnlySpan вместо строки. Вместо ручного парсинга чисел, можно записать фрагмент символов с числом в буфер и вызвать стандартный метод для парсинга.
Это решит проблему с парсингом чисел с плавающей точкой «дедовского» решения, а также сделает ввод кода удобнее, избавив от необходимости писать конструкции вида Console.ReadLine().Split().Select(int.Parse).ToArray() . Сам код настолько прост, что может быть легко написан прямо во время контеста (но не учитывает, например, переполнение буфера, если вам это важно):
SpanScanner
class Scanner < StreamReader input = new(Console.OpenStandardInput(), bufferSize: 16384); char[] buffer = new char[4096]; public int ReadInt() < var length = PrepareToken(); return int.Parse(buffer.AsSpan(0, length)); >private int PrepareToken() < int length = 0; bool readStart = false; while (true) < int ch = input.Read(); if (ch == -1) break; if (char.IsWhiteSpace((char)ch)) < if (readStart) break; continue; >readStart = true; buffer[length++] = (char)ch; > return length; > >
Program | Lang | Compiler | Mean (Int) | Mean (Double) |
---|---|---|---|---|
fastscan | C++ | g++64 | 14 ms | — |
fastscan | C# | NativeAOT | 22 ms | — |
Span | C# | NativeAOT | 38 ms | 85 ms |
cin | C++ | g++64 | 38 ms | 101 ms |
scanf | C++ | g++64 | 44 ms | 70 ms |
Console.ReadLine | C# | NativeAOT | 64 ms | 117 ms |
Да, работает медленнее «дедовского» варианта, но на уровне с общепринятыми способами ввода, не аллоцирует memory traffic, и уж точно не станет причиной попадания в Time или Memory Limit.
На C++ и других языках можно написать и более эффективные варианты консольного ввода. scanf и cin взяты только для того, чтобы ориентироваться на способы чтения ввода, которые обычно укладываются в пределы Time Limit
Для .NET 7 и C# 11 можно сделать generic версию на основе статического метода интерфейса ISpanParsable . Правда, в проверяющих системах C# 11 ещё не поддерживается.
SpanParsableScanner
class Scanner < StreamReader input = new(Console.OpenStandardInput(), bufferSize: 16384); char[] buffer = new char[4096]; public T Read() where T : ISpanParsable < var length = PrepareToken(); return T.Parse(buffer.AsSpan(0, length), CultureInfo.InvariantCulture); >private int PrepareToken() < int length = 0; bool readStart = false; while (true) < int ch = input.Read(); if (ch == -1) break; if (char.IsWhiteSpace((char)ch)) < if (readStart) break; continue; >readStart = true; buffer[length++] = (char)ch; > return length; > >
Также я подготовил более эффективный вариант кода на основе TryParse(ReadOnlySpan) , но он слишком длинный, чтобы поместиться здесь. Он разгоняется в моём тесте до 24 мс за счёт чтения данных блоками.
Отказываемся от StreamReader
StreamReader — прослойка между Console Stream, в который обычно попадают ASCII-символы и .NET-строками в кодировке UTF-16. Переделаем код для работы со Stream напрямую.
Метод для парсинга, принимающий ReadOnlySpan уже не подойдёт. К счастью, в .NET есть класс под названием Utf8Parser — наследие разработки библиотеки System.Text.Json , решающее ту же задачу для спана байтов. Не обманывайтесь тем, что в названии есть Utf8 — парсить все 100500 цифр, которые есть в Unicode он не умеет. Зато с обычными ASCII-цифрами справляется на ура!
Достоинство Utf8Parser.TryParse в сравнении с T.TryParse — возможность парсить значение с префикса, без заранее подготовленного токена. Сравните:
bool TryParse(ReadOnlySpan span, out int value, IFormatProvider provider); bool TryParse(ReadOnlySpan span, out int value, out int bytesConsumed, char format='\0')
Первый метод заставляет заранее заглянуть вперёд и найти разделитель. Затем данные читаются снова для парсинга.
Второй же умеет останавливаться при парсинге токена сам, позволяя распарсить данные за один проход по буферу.
Т.к. Utf8Parser — достаточно узкоспециализированный класс, он не поддерживает IFormatProvider и локали. Но нам это только в радость — десятичная запятая нам здесь никак не помешает.
При использовании Utf8Parser нужно учитывать, что если данных в буфере осталось мало — результат может оказаться неверным. Если какой-то из текстовых токенов разобьётся на два разных чтения из потока данных, например [. 12][34. ] , то Utf8Parser прочитает этот токен как два разных числа — 12 и 34. Или же для [. 1e][7. ] вернётся false для 1e , и придётся делать дополнительную проверку: или это невалидный double или же просто не хватило данных.
Для упрощения реализации, буду требовать наличия в буфере некоторого минимального количества данных или признака окончания потока данных. Сам код тоже довольно прост и занимается только загрузкой данных из потока и пропуском разделителей, которыми здесь считаются все символы по пробел включительно. По желанию можно также пропускать символы, например, с кодами >= 128 , на случай если в поток данных попадёт мусор.
Но во время контеста я бы лучше использовал предыдущий вариант на основе StreamReader и Span — он всё же гораздо проще
AsciiScanner
class Scanner < private const int MaxTokenLength = 1200; Stream? input = Console.OpenStandardInput(); byte[] buffer = new byte[32768]; SpanFragment => buffer.AsSpan(offset, length - offset); int offset; int length; public int ReadInt() < while (input != null && length - offset < MaxTokenLength) < if (offset != 0) < var remaining = Fragment.Length; Fragment.CopyTo(buffer); offset = 0; length = remaining; >var count = input.Read(buffer, length, buffer.Length - length); if (count length += count; while (offset < length && buffer[offset] while (offset < length && buffer[offset] void Throw() => throw new Exception(); >
Замеры
Program | Lang | Compiler | Mean (Int) | Mean (Double) |
---|---|---|---|---|
Utf8Parser | C# | NativeAOT | 10 ms | 40 ms |
fastscan | C++ | g++64 | 14 ms | — |
fastscan | C# | NativeAOT | 22 ms | — |
SpanBlock | C# | NativeAOT | 24 ms | 72 ms |
Span | C# | NativeAOT | 38 ms | 85 ms |
cin | C++ | g++64 | 38 ms | 101 ms |
scanf | C++ | g++64 | 44 ms | 70 ms |
Console.ReadLine | C# | NativeAOT | 64 ms | 117 ms |
В качестве тестовых данных использовался файл с 200000 строками шестизначных чисел по 4 числа в каждой (~5MB). Каждая программа считала XOR каждой из колонок и выводила ответ в конце. Таким образом, тестировалась только производительность ввода рассмотренными способами, с возможностью проверить корректность при тестировании. Входные данные предварительно загружались в память программы, производящей запуск тестируемых программ и подавались на stdin.
В качестве рантайма использовался .NET 7 NativeAOT на Linux. Этот вариант даёт меньше всего оверхеда на старте программы. C JIT на Windows оверхед составил ~36 мс, на Linux — ~70. Очерёдность по скорости для .NET-программ на Windows не отличается.
Тест не претендует на максимальную корректность, ставилась лишь цель оценить порядок разницы между способами чтения ввода.
Выводы
- На .NET можно писать программы с интенсивным консольным IO.
- Для достижения максимальной производительности рекомендуется:
- не использовать статические методы Console.Write/WriteLine , а писать в stdout через StreamWriter
- для чтения большого количества чисел с консоли (или просто для удобства написания кода) использовать описанные способы: например с дополнительным буфером и неаллоцирующим TryParse(ReadOnlySpan)
- правильно оценивать задачу и не переусложнять код без необходимости
Ссылки
- API Proposal о новом консольном вводе
C#. Урок 3. Консольный ввод\вывод
Backend-разработка и создание утилит командной строки невозможно без консольного ввода\вывода. В рамках данной статьи будут рассмотрены методы класса Console для чтения и записи информации в консоль.
- Консольный ввод\вывод
- Класс Console. Вывод данных в консоль
- Метод Write
- Метод WriteLine
- Метод Read
- Метод ReadLine
- Метод ReadKey
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
Консольный ввод\вывод
Все приложения условно можно разделить на две группы: консольные и с графическим интерфейсом пользователя. Ко второй группе относится большая часть приложений, с которыми работают пользователи в операционной системе Windows, на смартфонах и в вебе. Под консольными будем понимать приложения, которые запускаются через терминал (командную строку), их взаимодействие с пользователем происходит в текстовом режиме. Практически все приложения, которые запускаются на стороне сервера можно отнести к этой группе. Для организации ввода\вывода информации при работе с консолью в C# используется класс Console.
Класс Console. Вывод данных в консоль
Класс Console содержит методы для работы с консольным вводом\выводом, управлением потоком с ошибками и окном консоли. Начнем с вывода информации в консоль, для решения этой задачи класс Console предоставляет два метода: Write и WriteLine.
Для знакомства с методами класса Console создайте в удобном для вас каталоге проект с именем CSharpLesson3:
> dotnet new console -o CSharpLesson3
Метод Write
Метод Write – направляет в стандартный выходной поток текстовое представление переданного в него объекта. Дополнительно, предоставляет возможность задать форматирование.
Откройте файл Program.cs в созданном ранее проекте и добавьте в метод Main следующие строки, демонстрирующие работу с методом Write:
// Примеры работы с методом Write без форматирования Console.Write("Текущая дата: "); Console.Write(DateTime.Now); Console.Write("\n"); Console.Write($"Текущая дата: \n"); // Примеры работы с методом Write с использованием форматирования Console.Write("Текущая дата: \n", DateTime.Now); Console.Write("Число: \n", 123.456789);
Более подробно про форматирование будет написано в уроке, посвященном работе со строками.
Сохраните документ, откройте консоль, перейдите в каталог с проектом и выполните команду:
> dotnet run
Результат работы программы будет выглядеть примерно следующим образом:
Текущая дата: 16.10.2020 11:48:28 Текущая дата: 16.10.2020 11:48:28 Текущая дата: 16.10.2020 11:48:28 Текущая дата: 1,234568E+002
Обратите внимание на первые три вызова метода Write, если не поставить символ перевода строки, то данные будут выдаваться в одну строку друг за другом, это не всегда удобно. Если требуется, чтобы вывод каждый раз осуществлялся с новой строки, то воспользуйтесь методом WriteLine.
Метод WriteLine
Метод WriteLine записывает указанные данные в выходной поток и добавляет символ перевода строки. Добавьте в программу следующие строки:
Console.WriteLine("Текущая дата: "); Console.WriteLine(DateTime.Now);
Теперь надпись “Текущая дата:” и дата со временем будут выведены в разных строках.
WriteLine (также как Write) может принимать не только строковые значения, но и переменные разных типов:DateTime nowDate = DateTime.Now; string someText = "Сегодня"; int number = 924; Console.WriteLine(nowDate); Console.WriteLine(someText); Console.WriteLine(number);
Удобным и наглядным способом вывода значений переменных в консоль с дополнительным текстовым пояснением является использование строковой интерполяции:
Console.WriteLine($" . Число: ");
Запустите проект и в консоли увидите результат выполнения программы:
Сегодня 26.08.2020 11:53:44. Число: 924
Прием интерполяции позволяет внутри строки, используя фигурные скобки, указывать имена переменных, которые будут заменены значениями. Перед такой строкой ставится знак $.
Методы WriteLine и Write позволяют использовать форматирование:Console.WriteLine(":, Число: ", nowDate, someText, number);
В этом случае методу передается ряд параметров, первый – это строка, в которой, в фигурных скобках, указывается порядок подстановки значений переменных, далее, через запятую, перечисляются переменные, значения которых нужно подставить, здесь важен порядок: нумерация начинается с 0.
Класс Console. Чтение данных из консоли
В классе Console, помимо рассмотренных выше методов вывода в консоль, присутствуют методы для считывания вводимых данных из консоли.
Метод Read
Метод Read возвращает числовой код последнего введенного символа во входном потоке, если символ введен не был, то будет возвращен код -1. Для завершения работы метода, после ввода символа необходимо нажать клавишу “Enter”. Рассмотрим работу с методом Read на примере:
Console.WriteLine("Нажмите любую клавишу, а затем Enter"); int key1 = Console.Read(); Console.WriteLine($"Код нажатой клавиши: "); Console.WriteLine("Символьное представление: " + Convert.ToChar(key1));
Если после надписи “Нажмите любую клавишу, а затем Enter” будет введено более одного символа, то Read вернет только первый.
Для представления кода в виде символа необходимо переменную key1 привести к типу Char, для этого можно воспользоваться методом Convert.ToChar().
Метод ReadLine
Метод ReadLine возвращает введенную строку символов до нажатия клавиши “Enter”. Добавим несколько строк в файл с исходным кодом, для демонстрации работы с методом ReadLine :
Console.WriteLine("Введите ваше имя, а затем нажмите Enter"); string name = Console.ReadLine(); Console.WriteLine($"Привет, !");
Если необходимо получить с консоли численные данные, то следует воспользоваться методами из класса Convert для приведения типа String к соответствующему числовому типу:
Console.WriteLine("Сколько вам лет?"); int age = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("Ваш рост в см?"); int height = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("Привет , вам уже полных лет и ваш рост см", name, age, height);
Метод ReadKey
ReadKey возвращает объект класса ConsoleKeyInfo, в который помещается информация о нажатой клавише. Этот метод, как правило, используют для остановки выполнения программы или чтобы получить ответ от пользователя. Добавим строки для работы с ReadKey:
Console.WriteLine("Нажмите любую клавишу:"); var key2 = Console.ReadKey(); Console.WriteLine(key2.Key); Console.WriteLine(key2.KeyChar);
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.