2013-05-01 7 views
3

У меня есть функция с именем readNextString(ifstream &file , char* &pBuffer), которая извлекает следующую строку из файла, до достижения ',' или '\n', удаляет пробелы в начале и в конце строки, сохраняет остальное в pBuffer и возвращает true, если все работает нормально - false в противном случае. Все работает до тех пор, пока не будет достигнут конец файла. Когда установлен флаг eof, я не могу перенести указатель get. Я попытался это:Чтение из файла после достижения конца файла

if(file.eof()) 
{ 
    file.clear(); 
    file.seekg(0 , ios::end) 
} 

..., а затем удалить пробельные в конце строки. Это почти помогло. Функция извлекает строку без пробелов, но я получаю бесконечный цикл.

Мой фактический вопрос: как я могу проверить, является ли следующий символ EOF, и если я не могу - есть ли альтернативный способ сделать это?

Вот моя фактическая функция:

bool readNextString(ifstream &file , char* &pBuffer) 
{ 
    if(file.eof()){ 
     return false; 
    } 
    for(; file.good() && isWhitespace(file.peek()) && !file.eof() ; file.seekg(1 , ios::cur)) 
     ; 
    if(file.eof()){ 
     cout << "The file is empty.\n"; 
     return false; 
    }else{ 
     streamoff startPos = file.tellg(); 
     cout << "startPos : " << startPos << endl; 
     for(;file.good() && file.peek()!='\n' && file.peek()!=',' && file.peek()!= EOF; file.seekg(1 , ios::cur)) 
      ; 
     streamoff A = file.tellg(); 
     cout << "A : " << A << endl; 
     file.seekg(-1 , ios::cur); 
     for(;file.good() && isWhitespace(file.peek()) ; file.seekg(-1 , ios::cur)) 
      ; 
     file.seekg(2 , ios::cur); 
     streamoff endPos = file.tellg(); 
     cout << "endPos : " << endPos << endl; 
     pBuffer = new char[endPos-startPos]; 
     if(pBuffer) 
     { 
      file.seekg(startPos , ios::beg); 
      file.get(pBuffer , endPos-startPos , ',' || '\n'); 
      for(;file.good() && file.peek()!='\n' && file.peek()!=',' && file.peek()!= EOF; file.seekg(1 , ios::cur)) 
       ; 
      file.seekg(2 , ios::cur); 
      streamoff temp = file.tellg(); 
      cout << "temp : " << temp << endl; 
      return true; 
     }else{ 
      cout << "Error! Not enough memory to complete the task.\nPlease close some applications and try again.\n"; 
      return false; 
     } 
    } 
} 

И это единственное место, где я это называю:

void printCities() 
{ 
    ifstream city ; 
    city.open("cities.txt", fstream::in); 
    if(city.is_open()) 
    { 
     char *currCity; 
     int counter = 1; 
     while(readNextString(city , currCity)) 
     { 
      cout << counter++ << ". " << currCity << endl; 
      delete[] currCity; 
      currCity = NULL; 
     } 
     if(city.eof()) 
      cout << "There are no cities added.\n"; 
     city.close(); 
    }else 
     cout << "Error by opening 'cities.txt'.Make sure that the file exist and try again.\n"; 
} 

Надеется, что я достаточно ясно. Если вы обнаружите некоторые другие ошибки или возможные ошибки, я буду рад услышать их и узнать из него.

+0

FYI вы _really_ не хотите разбирать строки из такого файла. Либо прочитайте весь файл в буфер, либо прочитайте большие куски за раз в буфер и проанализируйте его в памяти. Не делайте миллионных чтений. Это медленно. И для этого на самом деле сложнее. – David

+0

@Dave Чтение символа по символу не обязательно медленное; 'istream' выполняет буферизацию. Однако использование seek _is_ медленное; во множестве реализаций поиск приведет к потере буфера и двум системным вызовам на символ. (Этого не нужно, но поиск в буфере должен быть достаточно редким, чтобы библиотека не оптимизировала их.) –

ответ

0

Ok.I сделал это иначе! getline() для WIN! : D Так что это мой код (на этот раз гораздо более удобным для чтения):

bool readNextString(ifstream &file , char pBuffer[]) 
{ 
    while(isWhitespace(file.peek()) && !file.eof()) 
     file.ignore(1); 
    if(!file.eof()) 
    { 
     streamoff start = file.tellg(); 
     stringstream toComma; 
     if(file.getline(pBuffer , 200 , ',')) 
     { 
      toComma << pBuffer; 
      toComma.getline(pBuffer ,200, '\n'); 
      int i=strlen(pBuffer)-1; 
      for(; isWhitespace(pBuffer[i]) ;i--) 
       ; 
      pBuffer[i+1] = '\0'; 
      file.clear(); 
      file.seekg(start + strlen(pBuffer) , file.beg); 
      return true; 
     }else return false; 
    } 
    return false; 
} 

Я сделал некоторые изменения в моей другой функции тоже:

void printCities() 
{ 
    ifstream city ; 
    city.open("cities.txt", fstream::in); 
    if(city.is_open()) 
    { 
     if(!isEmpty(city)) 
     { 
      char currCity[200]; 
      int counter = 1; 
      while(readNextString(city , currCity) && counter < 10) 
       cout << counter++ << ". " << currCity << endl; 
     }else 
      cout << "There are no cities added.\n"; 
     city.close(); 
    }else 
     cout << "Error by opening 'cities.txt'.Make sure that the file exist and try again.\n"; 
} 

Функциональный isEmpty(ifstream &file) возвращает истину, если файл пуст и false в противном случае.

Спасибо всем за помощь! С уважением!

3

Как проверить, является ли следующий символ EOF?

Как это

if (file.peek() == EOF) 
{ 
    // next char is EOF 
    ... 
} 
+0

Да, это в моем коде, но я не работает должным образом. Проблема возникает во втором цикле, когда я пытаюсь выяснить, где находится следующий «,», «\ n» или в этом случае EOF.Когда я проверяю позицию get pointer (tellg), в моем коде Я сохраняю его как «A», и он говорит, что позиция равна -1 ... :( – dragonator

+0

Я не уверен, но я ожидаю, что tellg не сработает, потому что вы пытались прочитать за конец файла. Попробуйте позвонить tellg before вы вызываете peek not after. – john

+0

Альтернативно попробуйте и упростите. Я не понял вашу проблему или прочитал другой ответ, но ваш код выглядит очень сложным. – john

1

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

Во-вторых, вы, кажется, неправильно понимаете значение istream::good() и istream::eof(). Существует никогда в любое время, где istream::good() уместно, и istream::eof() не обычно неподходящими после ввода имеет не удалось. Что касается вашего цикла прыгая белое пространство, обычное решение будет:

while (isspace(file.peek()) && file.peek() != EOF) { 
    file.get();  // ignore read character... 
} 

Аналогичные комментарии справедливы и для других циклов, а также, за исключением того, что вы не хотите, чтобы игнорировать символы чтения. Для того, чтобы собрать символов до следующего ',', например:

std::string field; 
while (file.peek() != ',' && file.peek() != EOF) { 
    field.push_back(file.get()); 
} 

(и ваш file.get(pBuffer, endPos - startPos, ',' || '\n') , конечно, не делать то, что вы ожидаете, что, выражение ',' || '\n' всегда будет вычисляться true, который, когда преобразуется к char, является '\01.)

Наконец, в то время как выше стратегия будет работать, это гораздо предпочтительнее для ввода больших блоков текста в std::stream и разобрать это.Если текст ориентирован на линию, используйте что-то вроде:

std::string line; 
while (std::getline(file, line)) { 
    // Parse line, using std::istringstream if appropriate, 
    // although this doesn't seem to be the case for your code. 
} 

Это на порядок проще, чем то, что вы делаете.

+0

Спасибо за подробный ответ, но я думаю, что это не помогает мне много ... 1. Первый код, который вы мне дали, почти равный моему, и он не работает должным образом. Это file.peek()! = EOF не работает. 2. Второй код на самом деле может помочь ... 3.О моем кодексе - я вас плохо понял, но я думаю, что он работает нормально, потому что проблема возникает только в конце файла ... 4 . И для getline() - это был мой второй вариант, но я хотел понять, как это сделать с помощью seekg ... это должен быть способ сделать это с помощью этого метода ... Опять же - большое спасибо за помощь :) – dragonator

+0

@dragonator 'file.peek()' никогда не сработает. Если 'file.peek()' возвращает 'EOF', это либо потому, что вы находитесь в конце файла, либо вы уже столкнулись с какой-либо ошибкой. И отдельные фрагменты кода объясняют разные ошибки: как только вы достигнете конца файла, «файл» потерпел неудачу, и никакие другие операции (включая поиск) не действительны на нем. Что касается 3, конечным условием для строки, которую я цитирую, является символ '0x01'. Или вы читаете точный счет: то, что вы, вероятно, хотели, было 'file.read (pBuffer, endPos - startPos)' (но это все еще не очень хорошее решение). –

+0

@dragonator Если целью является просто получить опыт работы с 'gseek()': вам, вероятно, придется называть 'file.clear()' непосредственно перед каждым поиском. Или используйте C++ 11 (который указывает, что 'eofbit' должен быть очищен в' seekg', _before_ чем-нибудь еще). –

Смежные вопросы