Как читать до EOF из Cin в C ++ - PullRequest
       54

Как читать до EOF из Cin в C ++

70 голосов
/ 14 октября 2008

Я пишу программу, которая считывает данные непосредственно из пользовательского ввода, и мне было интересно, как я мог (без циклов) считывать все данные до EOF из стандартного ввода. Я рассматривал возможность использования cin.get( input, '\0' ), но '\0' на самом деле не является символом EOF, он просто читает до EOF или '\0', в зависимости от того, что произойдет раньше.

Или использование циклов - единственный способ сделать это? Если да, то какой путь лучше?

Ответы [ 10 ]

62 голосов
/ 14 октября 2008

Единственный способ прочитать переменное количество данных из stdin - использовать циклы. Я всегда обнаруживал, что функция std::getline() работает очень хорошо:

std::string line;
while (std::getline(std::cin, line))
{
    std::cout << line << std::endl;
}

По умолчанию getline () читает до новой строки. Вы можете указать альтернативный символ завершения, но сам EOF не является символом, поэтому вы не можете просто сделать один вызов getline ().

46 голосов
/ 14 октября 2008

Вы можете сделать это без явных циклов, используя потоковые итераторы. Я уверен, что он использует какой-то цикл внутри.

#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;
}
40 голосов
/ 14 октября 2008

Использование циклов:

#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))
{
   ...
}

Ресурс

21 голосов
/ 02 мая 2016

После исследования решения 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 голосов
/ 18 мая 2015

Вероятно, самое простое и в целом эффективное:

#include <iostream>
int main()
{
    std::cout << std::cin.rdbuf();
}

При необходимости используйте поток других типов, таких как std::ostringstream, в качестве буфера вместо стандартного потока вывода.

2 голосов
/ 03 августа 2012

Грустное замечание: я решил использовать C ++ IO, чтобы соответствовать буст-коду. Из ответов на этот вопрос я выбрал while (std::getline(std::cin, line)). Используя g ++ версии 4.5.3 (-O3) в Cygwin (mintty), я получил пропускную способность 2 МБ / с. Microsoft Visual C ++ 2010 (/ O2) сделал это 40 МБ / с для того же кода.

После перезаписи ввода-вывода в чистый C while (fgets(buf, 100, stdin)) пропускная способность выросла до 90 МБ / с в обоих протестированных компиляторах. Это имеет значение для любого ввода больше 10 МБ ...

2 голосов
/ 14 октября 2008

Вы можете использовать std :: istream :: getline () (или, предпочтительно, версию , которая работает с std :: string ), чтобы получить всю строку. Оба имеют версии, которые позволяют указывать разделитель (символ конца строки). По умолчанию для строковой версии используется значение \ n.

0 голосов
/ 19 декабря 2014

Один вариант - использовать контейнер, например,

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();
}
0 голосов
/ 10 августа 2012

Подождите, я правильно вас понимаю? Вы используете 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();
    }
0 голосов
/ 26 мая 2011
while(std::cin) {
 // do something
}
...