Как читать до EOF от cin в С++
Я кодирую программу, которая считывает данные непосредственно с пользовательского ввода, и задавался вопросом, как я мог (без циклов) читать все данные до тех пор, пока EOF не будет со стандартного ввода. Я рассматривал возможность использования cin.get( input, '\0' )
, но '\0'
на самом деле не является символом EOF, который просто читается до EOF или '\0'
, в зависимости от того, что наступит раньше.
Или использует циклы единственный способ сделать это? Если да, то какой лучший способ?
Ответы
Ответ 1
Единственный способ, которым вы можете читать переменную сумму данных из stdin, - это использование циклов. Я всегда обнаружил, что функция std::getline()
работает очень хорошо:
std::string line;
while (std::getline(std::cin, line))
{
std::cout << line << std::endl;
}
По умолчанию getline() читает до новой строки. Вы можете указать альтернативный символ окончания, но EOF сам по себе не является символом, поэтому вы не можете просто сделать один вызов getline().
Ответ 2
Вы можете сделать это без явных циклов с помощью итераторов потоков. Я уверен, что он использует какой-то цикл внутри.
#include <string>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
int main()
{
// don't skip the whitespace while reading
std::cin >> std::noskipws;
// use stream iterators to copy the stream to a string
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string results(it, end);
std::cout << results;
}
Ответ 3
Использование циклов:
#include <iostream>
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
...
}
// lines
string line;
while (getline(cin, line))
{
...
}
// characters
char c;
while (cin.get(c))
{
...
}
ресурс
Ответ 4
После исследования решения KeithB с использованием std::istream_iterator
я обнаружил std:istreambuf_iterator
.
Протестируйте программу, чтобы прочитать весь входной канал в строку, затем запишите его снова:
#include <iostream>
#include <iterator>
#include <string>
int main()
{
std::istreambuf_iterator<char> begin(std::cin), end;
std::string s(begin, end);
std::cout << s;
}
Ответ 5
Вероятная простейшая и обычно эффективная:
#include <iostream>
int main()
{
std::cout << std::cin.rdbuf();
}
При необходимости используйте поток других типов, например std::ostringstream
, в качестве буфера вместо стандартного потока вывода.
Ответ 6
Вы можете использовать std:: istream:: getline() (или предпочтительно которая работает на std::string), чтобы получить целую строку. У обоих есть версии, которые позволяют указать разделитель (конец строки). По умолчанию для версии строки указано "\n".
Ответ 7
Замечание со стороны: я решил использовать С++ IO для согласования с кодом на основе boost. Из ответов на этот вопрос я выбрал while (std::getline(std::cin, line))
. Используя g++ версию 4.5.3 (-O3) в cygwin (mintty), я получил пропускную способность 2 МБ/с. Microsoft Visual С++ 2010 (/O2) сделал это 40 Мбайт/с для того же кода.
После перезаписи ввода-вывода до чистого C while (fgets(buf, 100, stdin))
пропускная способность подскочила до 90 МБ/с в обоих тестируемых компиляторах. Это имеет значение для любого ввода, превышающего 10 МБ...
Ответ 8
while(std::cin) {
// do something
}
Ответ 9
Подождите, я правильно понимаю вас? Вы используете cin для ввода с клавиатуры, и хотите прекратить чтение ввода, когда пользователь вводит символ EOF? Почему пользователь должен вводить символ EOF? Или вы имели в виду, что хотите прекратить чтение из файла в EOF?
Если вы на самом деле пытаетесь использовать cin для чтения символа EOF, то почему бы просто не указать EOF в качестве разделителя?
// Needed headers: iostream
char buffer[256];
cin.get( buffer, '\x1A' );
Если вы хотите прекратить чтение из файла в EOF, просто используйте getline и еще раз укажите EOF в качестве разделителя.
// Needed headers: iostream, string, and fstream
string buffer;
ifstream fin;
fin.open("test.txt");
if(fin.is_open()) {
getline(fin,buffer,'\x1A');
fin.close();
}
Ответ 10
Один из вариантов заключается в использовании контейнера, например
std::vector<char> data;
и перенаправить все входные данные в эту коллекцию до тех пор, пока не будет получена EOF
, т.е.
std::copy(std::istream_iterator<char>(std::cin),
std::istream_iterator<char>(),
std::back_inserter(data));
Однако используемому контейнеру может потребоваться перераспределение памяти слишком часто, иначе вы закончите с исключением std::bad_alloc
, когда ваша система выйдет из памяти. Чтобы решить эти проблемы, вы можете зарезервировать фиксированную сумму элементов N
и обработать это количество элементов в изоляции, то есть
data.reserve(N);
while (/*some condition is met*/)
{
std::copy_n(std::istream_iterator<char>(std::cin),
N,
std::back_inserter(data));
/* process data */
data.clear();
}