Чтение С++ из файла помещает три странных символа

Когда я читаю из файла строку за строкой, операция >> получает первую строку, но начинается с "i" . Предположим, что первая строка — это «street», затем она становится «ï»¿istreet.

Остальные струны в порядке. Пробовал разные txt файлы. Результат тот же. Первая строка начинается с «ï»¿i». В чем проблема?

Вот мой код:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int cube(int x){ return (x*x*x);}

int main(){

int maxChar;
int lineLength=0;
int cost=0;

cout<<"Enter the max char per line... : ";
cin>>maxChar;
cout<<endl<<"Max char per line is : "<<maxChar<<endl;

fstream inFile("bla.txt",ios::in);

if (!inFile) {
    cerr << "Unable to open file datafile.txt";
    exit(1);   // call system to stop
}

while(!inFile.eof()) {
    string word;

    inFile >> word;
    cout<<word<<endl;
    cout<<word.length()<<endl;
    if(word.length()+lineLength<=maxChar){
        lineLength +=(word.length()+1);
    }
    else {
        cost+=cube(maxChar-(lineLength-1));
        lineLength=(word.length()+1);
    }   
}

}

person vkx    schedule 02.05.2012    source источник
comment
Кроме того: Никогда не используйте .eof() в качестве условия цикла. Он почти всегда производит глючный код, как и в вашем случае. Предпочтительно выполнять операцию ввода в условиях цикла: string word; while(inFile >> word) { … }.   -  person Robᵩ    schedule 02.05.2012


Ответы (3)


Вы видите знак порядка байтов (BOM) UTF-8. Он был добавлен приложением, создавшим файл.

Чтобы обнаружить и игнорировать маркер, вы можете попробовать эту (непроверенную) функцию:

bool SkipBOM(std::istream & in)
{
    char test[4] = {0};
    in.read(test, 3);
    if (strcmp(test, "\xEF\xBB\xBF") == 0)
        return true;
    in.seekg(0);
    return false;
}
person Mark Ransom    schedule 02.05.2012
comment
Также вы можете упомянуть, что он неправильно читает файл; должно быть while (inFile >> word) а не while (!inFile.eof()) - person Seth Carnegie; 02.05.2012
comment
@vk7x stackoverflow.com/questions/8880548/ - person James Custer; 02.05.2012
comment
Приведенный выше код не будет работать, если вы не добавите приведение (unsigned char) перед оператором if, например. if ((unsigned char)test[0] == 0xEF && (unsigned char)test[1] == 0xBB && (unsigned char)test[2] == 0xBF). Либо так, либо сравните с -17, -69 и -65. Смотрите мой ответ ниже. - person Contango; 20.06.2013
comment
@Contango, я не знаю, почему я так долго не мог увидеть твой комментарий, но спасибо. Я придумал совершенно другой способ решения проблемы, смотрите мою последнюю правку. - person Mark Ransom; 09.03.2014

Ссылаясь на превосходный ответ Марка Рэнсома выше, добавление этого кода пропускает спецификацию (знак порядка байтов) в существующем потоке. Вызовите его после открытия файла.

// Skips the Byte Order Mark (BOM) that defines UTF-8 in some text files.
void SkipBOM(std::ifstream &in)
{
    char test[3] = {0};
    in.read(test, 3);
    if ((unsigned char)test[0] == 0xEF && 
        (unsigned char)test[1] == 0xBB && 
        (unsigned char)test[2] == 0xBF)
    {
        return;
    }
    in.seekg(0);
}

Использовать:

ifstream in(path);
SkipBOM(in);
string line;
while (getline(in, line))
{
    // Process lines of input here.
}
person Contango    schedule 20.06.2013

Вот еще две идеи.

  1. если вы тот, кто создает файлы, сохраните их длину вместе с ними, и при их чтении просто обрежьте все префиксы с помощью этого простого вычисления: trueFileLength - saveFileLength = numOfByesToCut
  2. создайте свой префикс при сохранении файлов, а при чтении ищите его и удаляйте все, что вы нашли раньше.
person Ilya Gazman    schedule 02.05.2012