Arun Sharma
Arun Sharma

Reputation: 517

Read content of text file in c++ line wise

I want to show the content of text file 20 lines on screen. User press 'n' to show next 20 lines and 'p' to show previous 20 lines. I don't know why its not working.

Here is my code:

#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);
        }
    }
}

Upvotes: 0

Views: 1006

Answers (3)

Michael J
Michael J

Reputation: 7939

Here is a suggested implementation. Feel free to ask questions about how it works, if that is not clear.

Among the main features

  • Uses std::string instead of char *
  • Is broken into small-ish functions
  • Uses a class to encapsulate the data and methods

    #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;
    }
    

Upvotes: 0

Sceptical Jule
Sceptical Jule

Reputation: 917

I wouldn't do it so complex. Just read the file to a vector at program start and catch keyboard input (not tested):

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;
//...

Upvotes: 0

TypeIA
TypeIA

Reputation: 17248

First, s is uninitialized, so f.getline(s,100) is undefined behavior (it's writing to some arbitrary location in memory).

Next, your for loop counts to 25, not 20. I assume this is a simple typo either in the code or the question/comment.

Finally, your seek logic is incorrect. You're rereading pos each time you read a line of text, so you're only going to seek back one line, not 20/25 lines. Moreover the argument to seekg() is an absolute position, so you shouldn't negate it.

EDIT: You should also initialize pos to zero, so that if the first key the user presses is p you seek to the beginning of the file. Otherwise if p is the first keypress the behavior is undefined since you're seeking to an uninitialized offset.

You should also check for EOF each time you try to read a line, so that your program behaves correctly when the end of the file is reached.

Upvotes: 1

Related Questions