【问题标题】:Read content of text file in c++ line wise以 C++ 逐行读取文本文件的内容
【发布时间】:2013-12-27 16:30:59
【问题描述】:

我想在屏幕上显示 20 行文本文件的内容。 用户按“n”显示下 20 行,按“p”显示前 20 行。 我不知道为什么它不起作用。

这是我的代码:

#include<fstream.h>
#include<process.h>
#include<conio.h>
void main()
{
    clrscr();
    char *s,key;
    int pos;
    fstream f;
    f.open("menu.cpp",ios::in);
    while(1)
    {
        key=getch();
        switch(key)
        {
            case 'n':
                    //read more 20 lines
                    clrscr();
                    for(int i=1;i<=25;i++)
                    {
                        f.getline(s,100);
                        pos=f.tellg();
                        cout<<s<<endl;
                    }
                    break;
            case 'p':   //read previous 20 lines
                    clrscr();
                    f.seekg(-pos);
                                        for(int i=1;i<=25;i++)
                    {
                        f.getline(s,100);

                        cout<<s<<endl;
                    }
                                        break;
            case 'e':
                    clrscr();
                    cout<<"exit";
                    exit(0);
        }
    }
}

【问题讨论】:

  • 您可能还应该发布它实际在做什么,这样人们就不必编译和运行程序。和/或您收到的任何错误消息。
  • 哦..我忘了提...接下来的 20 行显示正确,但是当我按“p”时,前 20 行没有显示,然后当我按“e”时程序也不退出。

标签: c++ file text lines


【解决方案1】:

首先,s 未初始化,因此f.getline(s,100) 是未定义的行为(它正在写入内存中的某个任意位置)。

接下来,您的 for 循环计数为 25,而不是 20。我认为这是代码或问题/评论中的简单错字。

最后,您的搜索逻辑不正确。每次阅读一行文本时,您都在重读 pos,因此您只会返回一行,而不是 20/25 行。而且seekg()的参数是一个绝对位置,所以你不应该否定它。

编辑:您还应该将pos 初始化为零,这样如果用户按下的第一个键是p,您就会找到文件的开头。否则,如果 p 是第一次按键,则行为未定义,因为您正在寻找未初始化的偏移量。

您还应该在每次尝试读取一行时检查 EOF,以便在到达文件末尾时您的程序行为正确。

【讨论】:

  • 但我认为如果我将提供 pos 的 -ve 值,seekg() 函数会向后移动文件指针。那么最后你的建议是什么?
  • @ArunSharma 仅当您使用 2 参数版本并指定 ios_base::cur 时。 seekg() 的 1 参数版本采用绝对文件位置。见cplusplus.com/reference/istream/istream/seekg
  • @ArunSharma seekg 的单参数形式的实参不是整数类型;据我所知,一元 - 不是,也不应该为它定义。 (VC++ 和 g++ 似乎都定义了它,但它们并没有告诉我语义是什么。当然,streampos(-1) 用于表示错误。)
【解决方案2】:

我不会做这么复杂的。只需在程序启动时将文件读取到向量并捕获键盘输入(未测试):

std::vector<std::string> fileContent;
std::string line;
while (std::getline(infile, line))
    fileContent.push_back(line);  // in the end, the file is stored in the STL container

unsigned long lineTracker = 0;  //to make the whole thing buffer-overflow-safe
while(true)
{
    key = getch();
    switch(key)
    {
        case 'n':
            //read more 20 lines
            clrscr();
            for (unsigned i = 0; i < 20 && lineTracker < fileContent.size(); ++i, ++lineTracker)
                std::cout << fileContent[lineTracker];
            break;

        case 'p':
            clrscr();
            lineTracker -= 20;
            for (unsigned i = 0; i < 20 && lineTracker >= 0; ++i, ++lineTracker)
                std::cout << fileContent[lineTracker];
            break;
//...

【讨论】:

    【解决方案3】:

    这是一个建议的实现。如果不清楚,请随时询问有关其工作原理的问题。

    主要功能中

    • 使用 std::string 代替 char *
    • 被分解成小的函数
    • 使用类来封装数据和方法

      #include <string>
      #include <vector>
      #include <iostream>
      #include <fstream>
      #include <conio.h>  // for getch()
      
      class CFileViewer
      {
      public:
          CFileViewer(const std::string &sFileName);
          void Show();
      
      protected:
          void InitFile(const std::string &sFileName);
          void ShowPage();
          bool GetInput();
          static size_t LinesPerPage() { return 25; };
      
      private:
          size_t                 m_nPage;
          std::vector<long long> m_vPos;
          std::ifstream          m_file;
      };
      
      CFileViewer::CFileViewer(const std::string &sFileName)
      : m_nPage(0)
      {
          m_vPos.push_back(0);
          InitFile(sFileName);
      }
      
      void CFileViewer::InitFile(const std::string &sFileName)
      {
          m_file.open(sFileName);
          if (!m_file)
              throw std::runtime_error("cannot open file");
      }
      
      void CFileViewer::ShowPage()
      {
          // clear any previous eof state
          m_file.clear();
      
          // goto required part of file
          m_file.seekg(m_vPos.at(m_nPage));
      
          std::string s;
          for (size_t i=0; i<LinesPerPage(); ++i)
          {
              if (std::getline(m_file, s))
                  std::cout << s << std::endl;
              else if (m_file.eof())
                  break;
              else
                  throw std::runtime_error("error reading file");
          }
          // if we just read a page and it was the last in m_vPos, save
          // current pos as start of next page
          // NB m_nPage will not be incremented if we're at eof.
          if (!m_file.eof() && ++m_nPage == m_vPos.size())
              m_vPos.push_back(m_file.tellg());
      }
      
      bool CFileViewer::GetInput()
      {
          while (1)
          {
              switch (_getch())
              {
                  case 'p':
                      if (m_nPage > 1)
                          m_nPage -= 2;
                      else
                          m_nPage = 0;
                      return true;
      
                  case 'e':
                      std::cout << "exit\n";
                      return false;
      
                  case 'n':
                      if (!m_file.eof())
                          return true;
                      // else
                      std::cout << "at eof\n";
                      // fall through
      
                  default:
                      putchar('\a');
              }
          }
      }
      
      void CFileViewer::Show()
      {
          do
          {
              ShowPage();
          }
          while (GetInput());
      }
      
      
      int main()
      {
          try
          {
              CFileViewer fv("menu.txt");
              fv.Show();
          }
          catch (std::exception &e)
          {
              std::cerr << e.what() << std::endl;
          }
          return 0;
      }
      

    【讨论】:

      猜你喜欢
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 2014-06-13
      • 2014-06-21
      相关资源
      最近更新 更多