C++: проблема с ifstream::getline

Я читаю такой файл:

char string[256];

std::ifstream file( "file.txt" ); // open the level file.

if ( ! file ) // check if the file loaded fine.
{
    // error
}

while ( file.getline( string, 256, ' ' )  )
{
    // handle input
}

Просто для целей тестирования мой файл состоит всего из одной строки с пробелом в конце:

12345 

Мой код сначала успешно читает 12345. Но затем вместо завершения цикла он читает другую строку, которая кажется возвратом/новой строкой.

Я сохранил свой файл как в gedit, так и в nano. И еще я вывел его с помощью команды Linux cat, и в конце нет возврата. Так что файл должен быть в порядке.

Почему мой код читает возврат/новую строку?

Спасибо.


person Community    schedule 16.01.2011    source источник
comment
не будет; решить проблему. Но используйте getline(std::istream&, std::string&), найденный в ‹string›, он принимает поток и std::string.   -  person Martin York    schedule 16.01.2011
comment
Вы уверены, что файл не содержит пустой строки. Скопируйте его с помощью шестнадцатеричного редактора, чтобы быть уверенным.   -  person Martin York    schedule 16.01.2011
comment
@Martin относительно вашего первого комментария, зачем мне это делать? Что касается вашего второго комментария, я постараюсь проверить. но я вывел файл с помощью команды Linux cat, и новой строки не было.   -  person    schedule 16.01.2011
comment
Какие символы он специально читает после строки?   -  person tiagovrtr    schedule 16.01.2011
comment
@tiagovtr, когда я вывожу строку, это просто приводит к возврату/новой строке   -  person    schedule 16.01.2011
comment
@ Мартин хммм ... в конце файла есть 0A ... может ли это быть виновником?   -  person    schedule 16.01.2011
comment
@Jay: используйте версию getline(std::istream&, std::string&), потому что максимальная длина строки не всегда может быть 256. Стоит подумать заранее.   -  person Martin York    schedule 16.01.2011
comment
@Джей: Да. 0A может быть виновником. Но это зависит от предыдущих символов. Файл представляет собой короткий дамп всех шестнадцатеричных значений. Если у вас нет соответствующих инструментов, я разместил код ниже, чтобы помочь.   -  person Martin York    schedule 16.01.2011
comment
@Мартин 31 32 33 34 35 20 0A   -  person    schedule 16.01.2011
comment
@Jay: Это выглядит хорошо. У меня есть еще один образец ниже.   -  person Martin York    schedule 16.01.2011
comment
@ Мартин, да, это было из программы с графическим интерфейсом. см. мой комментарий к вашему ответу о том, что вывели другие программы.   -  person    schedule 16.01.2011


Ответы (4)


Сначала убедитесь, что ваш входной файл в порядке:

Запустите следующую команду и сообщите нам результат:

#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
#include <fstream>>
#include <iomanip>
#include <algorithm>

int main()
{
    std::ifstream file("file.txt");
    std::cout << std::hex;

    std::copy(std::istreambuf_iterator<char>(file),
              std::istreambuf_iterator<char>(),

              std::ostream_iterator<int>(std::cout, " ")); 
}

Редактировать:

Выход был 31 32 33 34 35 20 0А

Попробуйте запустить этот код и посмотрите, что получится на выходе:

#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
#include <fstream>>
#include <iomanip>
#include <algorithm>

int main()
{
    std::ofstream file("file.txt");
    file << "12345 \n";
}

Скопируйте вывод этого файла и сравните его с оригиналом.
Проблема в том, что разные платформы имеют разную последовательность завершения строки. Я просто хочу убедиться, что «0x0A» — это последовательность завершения строки для вашей платформы. Обратите внимание, что последовательность завершения строки преобразуется в '\n' при чтении файла в текстовом режиме, а когда вы выводите '\n' в файл в текстовом режиме, она преобразуется в последовательность завершения строки.

Редактировать 2

Итак, у меня есть файл: file.txt

> od -ta -tx1 file.txt
0000000    1   2   3   4   5  sp  nl                                    
           31  32  33  34  35  20  0a                                    
0000007

Таким образом, файл содержит 1 строку, оканчивающуюся на 0x0A.

Используя эту программу:

#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
#include <fstream>>
#include <iomanip>
#include <algorithm>

int main()
{
    std::ifstream   file("file.txt");

    std::string line;
    while(std::getline(file,line))
    {
        std::cout << "Line(" << line << ")\n";
    }
}

Я получил:

> g++ t.cpp
> ./a.out
Line(12345 )
person Martin York    schedule 16.01.2011
comment
@Jay: Или запустите hexdump или od или xxd, если они есть в вашей системе. - person ephemient; 16.01.2011
comment
Если у вас есть инструменты, используйте их. Это просто предоставлено, потому что я предполагаю, что вы работаете в Windows и не имеете доступа к этим инструментам. - person Martin York; 16.01.2011
comment
Я на Linux... hexdump: 0000000 3231 3433 2035 000a 0000007 ; od: 0000000 031061 032063 020065 000012 0000007 ; xxd: 0000000: 3132 3334 3520 0a 12345 . мой комментарий к ОП был тем, что мне дала программа с графическим интерфейсом. - person ; 16.01.2011
comment
@martin Я сбросил вывод файла, полученного в результате вашего нового кода, и он был таким же: 31 32 33 34 35 20 0A. так что мой файл кажется плохим, правильно? - person ; 16.01.2011
comment
@Jay: Если вывод из файла такой же, то вход хороший. - person Martin York; 16.01.2011
comment
@ Мартин, подожди, я в замешательстве. что мы выяснили здесь, так это то, что мой исходный файл / имел / имел возврат / новую строку в конце, и это было причиной проблемы, верно? - person ; 16.01.2011
comment
@Jay: я тоже в замешательстве. Ваш исходный код должен работать с предоставленным вами входным файлом. Мое последнее обновление показывает, что файл, который вы используете со стандартным getline(), будет читать единственную строку в файле. В вашем коде происходит что-то еще. Вероятно, под битом /* дескриптор ввода */. Но я не могу воспроизвести вашу проблему с имеющейся у нас информацией. - person Martin York; 17.01.2011
comment
@Martin Я использую метод getline для чтения до пробела, а не \n. так что моя проблема, по-видимому, в том, что он читает \n в конце файла. есть ли способ, чтобы мой файл /не/ имел \n в конце, или это необходимо? и если это так, как мне заставить мой код не читать его? - person ; 17.01.2011
comment
@Джей: хорошо. Теперь я вижу, что происходит. Да, вполне возможно иметь файл, в котором нет последовательности завершения строки. К сожалению, большинство инструментов (особенно редакторов) добавляют его автоматически. Но если вы удалите 0x0A, ваш код должен работать. - person Martin York; 17.01.2011

это работает...

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

ifstream file("file.txt");

int main()
{
   string tmp="",st="";

   while (!file.eof())
    {
      file>>tmp;  
      if (tmp != "") st+=tmp;
      tmp="";  
    }
   cout<<st<<endl; 

   return 0;
}

входной файл.txt: 1 2 3 4 5
ответ: 12345

person Elmi Ahmadov    schedule 16.01.2011
comment
извините, это все еще неактуально. - person ; 16.01.2011
comment
Здесь нет никаких изменений по сравнению с ОП. за исключением того, что он более неуклюжий. Я бы сказал, что это стандартный антишаблон для чтения файла. Я не уверен, что стандарт определяет содержимое tmp, когда getline() не работает (могу ошибаться). - person Martin York; 16.01.2011

Попробуйте так:

while ( !file.eof()  )
{
    file.getline( string, 256, ' ' );
        // handle input
}
person tiagovrtr    schedule 16.01.2011
comment
@tiagovtr да, именно это я и делал изначально. это не сработало. и код в OP в любом случае лучше: stackoverflow.com/questions/3511110/ - person ; 16.01.2011
comment
Нет. eof() не является истинным, пока вы не попытаетесь прочитать его. Таким образом, вы, возможно, прочитали весь файл и все еще входите в цикл. В этот момент вы выполняете getline(), и он терпит неудачу. Тогда вы handling input, когда строка неверна. - person Martin York; 16.01.2011
comment
@Martin, ваш комментарий направлен на ответ @tiagovtr, верно? - person ; 16.01.2011
comment
@Джей: Да. Этот комментарий для этого ответа. - person Martin York; 16.01.2011

Это старо, но, похоже, для этого нет подходящего разрешения.

Я удивлен, что никто не заметил, что он использует разделитель пробелов. Из-за этого не будет прочитана вся строка, а только до первого пробела. Таким образом, getline по-прежнему будет иметь больше данных для чтения, прежде чем встретится с EOF.

Таким образом, следующая строка getline будет читать новую строку и возвращать то же самое, что и разделитель. Если бы вызов getline был таким:

файл.getline (строка, 256)

он не вернет новую строку и завершится за один шаг.

person SRK    schedule 19.03.2020
comment
Первый комментарий к этому вопросу предлагает такое же решение, поэтому, возможно, этот ответ можно было бы конструктивно сформулировать для новых читателей, чтобы они могли легко применить это решение. На вопрос есть принятый ответ, поэтому это не будет первым ответом, который люди прочитают, если он не получит голосов. - person Daniel Persson; 19.03.2020