阅读时它没有到达文件末尾

时间:2018-01-28 06:38:30

标签: c++ file

我已经创建了一个函数来根据一些规则分析文件中的文本。

void parse(const char *fileName){
    ifstream f;
    f.open("test.txt");
    char ch;
    string str = "";
    while(!f.eof()){
        f.get(ch);
        if(isspace(ch)){
            cout << ch << " -> Space." << endl;
        } else if(ch == '/'){
            cout << ch << " -> Symble." << endl;
        } else if(isalpha(ch)){
            str = ch;
            f.get(ch);
            while(isalnum(ch)){
                str += ch;
                f.get(ch);
            }
            f.putback(ch);
            cout << str << " -> String." << endl;
        } else if(isdigit(ch)){
            str = ch;
            f.get(ch);
            while(isdigit(ch)){
                str += ch;
                f.get(ch);
            }
            f.putback(ch);
            cout << str << " -> Number." << endl;
        } else {
            cout << ch << " -> Wrong value." << endl;
        }
    }
    f.close();
}

// The implementation
int main(){
    parse("test.txt");
    return 0;
}

test.txt的内容,例如:

  狮子王200 26/12/1910

在搜索到达最后一个字符时发现的问题后,它会不断重复,并且没有到达文件的末尾。

调试窗口:

结果:

如何使功能到达文件末尾?

(+)解决问题的方法,但不是最好的方法。

我已经解决了这个问题但在我看来使用了一种不好的方法,我已经在几个地方设置了一个条件来知道我是否已经到达文件的末尾。 if(f.eof()) break;

void parse(const char *fileName){
    ifstream f;
    f.open("test.txt");
    char ch;
    string str = "";
    while(!f.eof()){
        f.get(ch);
        if(isspace(ch)){
            if(f.eof()) break;
            cout << ch << " -> Space." << endl;
        } else if(ch == '/'){
            if(f.eof()) break;
            cout << ch << " -> Symble." << endl;
        } else if(isalpha(ch)){
            str = ch;
            f.get(ch);
            while(isalnum(ch)){
                str += ch;
                f.get(ch);
                if(f.eof()) break;
            }
            cout << str << " -> String." << endl;
            if(f.eof()) break;
            f.putback(ch);
        } else if(isdigit(ch)){
            str = ch;
            f.get(ch);
            while(isdigit(ch)){
                str += ch;
                f.get(ch);
                if(f.eof()) break;
            }
            cout << str << " -> Number." << endl;
            if(f.eof()) break;
            f.putback(ch);
        } else {
            if(f.eof()) break;
            cout << ch << " -> Wrong value." << endl;
        }
    }
    f.close();
}

还有另一种好方法吗?

3 个答案:

答案 0 :(得分:0)

当它达到EOF(或任何类型的失败)时,f.get(ch)不会更改ch

        while(isdigit(ch)){
            str += ch;
            f.get(ch);
        }

因此,您只是停留在此循环中,并继续将最后一个ch追加到str

确保您实际检查EOF而不是依赖isdigit(ch)

        while(isdigit(ch)){
            str += ch;
            if (!f.get(ch)) break;
        }

来自CppReference

basic_istream& get( char_type& ch );
     

读取一个字符并将其存储到ch (如果有)。否则,保留ch未经修改并设置failbiteofbit。请注意,与格式化字符输入signed char不同,此类函数不会在unsigned charoperator>>类型上重载。

答案 1 :(得分:0)

需要重新考虑处理从流中读取输入的一般方法。每次从流中读取时,必须先验证读取是否成功,然后再继续使用从流中读取的值。

最好使用if (f) / while (f)代替if (f.eof()) / while (f.eof())

这是您应该运行的功能的更新版本。

void parse(const char *fileName){
   ifstream f;
   f.open("test.txt");
   char ch;
   string str = "";

   // If a char can't be read, don't enter the loop.
   while(f.get(ch))
   {
      if(isspace(ch)){
         cout << ch << " -> Space." << endl;
      } else if(ch == '/'){
         cout << ch << " -> Symble." << endl;
      } else if(isalpha(ch)){
         str = ch;

         // Read the character and proceed to isalnum only
         // if read was successful.
         while(f.get(ch) && isalnum(ch)){
            str += ch;
         }
         cout << str << " -> String." << endl;

         // Don't call putback unless the stream is still in a no error state.
         if ( f ) {
            f.putback(ch);
         }
      } else if(isdigit(ch)){
         str = ch;
         // Read the character and proceed to isdigit only
         // if read was successful.
         while(f.get(ch) && isdigit(ch)){
            str += ch;
         }
         cout << str << " -> Number." << endl;

         // Don't call putback unless the stream is still in a no error state.
         if ( f ) {
            f.putback(ch);
         }
      } else {
         if(!f) break;
         cout << ch << " -> Wrong value." << endl;
      }
   }
   f.close();
}

一些使功能更简单的建议。

建议1

联合

ifstream f;
f.open("test.txt");

到一行

ifstream f("test.txt");

建议2

您正在传递fileName作为参数,但在函数中具有硬编码文件名test.txt。我认为最好使用fileName

ifstream f(fileName);

建议3

行中没有坏处

f.close();

但这是不必要的。函数返回时文件将被关闭。

建议4

您可以通过读取文本行并处理行来处理文件的内容,而不是通过函数调用在多个位置一次读取一个字符。它还允许您使功能更简单。您可以创建较小的函数以使代码更简单。

std::string::iterator parseAlphaNumeric(std::string::iterator start,
                                        std::string::iterator end)
{
   // Iterate over the string until we reach the end of the
   // line or the first character that is not an alphanumeric character.
   std::string::iterator iter = start;
   for ( ++iter; iter != end && isalnum(*iter); ++iter );

   // Create a string using the itertors instead of
   // adding to the string one character at a time.
   std::cout << std::string(start, iter) << " -> String." << std::endl;

   // The iterator now points to either the end of the line
   // or the first character that is not an alphanumeric character.
   return iter;
}

std::string::iterator parseNumeric(std::string::iterator start,
                                   std::string::iterator end)
{
   // See comments in the previous function.

   std::string::iterator iter = start;
   for ( ++iter; iter != end && isdigit(*iter); ++iter );
   std::cout << std::string(start, iter) << " -> Number." << std::endl;
   return iter;
}

void parseLine(std::string::iterator iter,
               std::string::iterator end)
{
   while ( iter != end )
   {
      char ch = *iter;
      if(isspace(ch)){
         std::cout << ch << " -> Space." << std::endl;
         ++iter;
      } else if(ch == '/'){
         std::cout << ch << " -> Symble." << std::endl;
         ++iter;
      } else if(isalpha(ch)){
         iter = parseAlphaNumeric(iter, end);
      } else if(isdigit(ch)){
         iter = parseNumeric(iter, end);
      } else {
         std::cout << ch << " -> Wrong value." << std::endl;
         ++iter;
      }
   }
}

void parse(const char *fileName){
   std::ifstream f(fileName);

   // Read lines of text and process each line.
   std::string line;
   while(getline(f, line))
   {
      parseLine(line.begin(), line.end());
   }
}

答案 2 :(得分:-1)

因为你把符号放回去,所以很可能流不会结束:

f.get(ch);
// ...
f.putback(ch);

另请注意,您应该在每次get调用后检查流状态,而不是每次循环迭代检查一次。