Я хочу показать содержимое текстового файла 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);
}
}
}
Во-первых, s
не инициализируется, поэтому f.getline(s,100)
является неопределенным поведением (он записывается в произвольное место в памяти).
Затем ваш цикл for
равен 25, а не 20. Я предполагаю, что это простая опечатка либо в коде, либо в вопросе/комментарии.
Наконец, ваша логика поиска неверна. Вы перечитываете pos
каждый раз, когда вы читаете строку текста, поэтому вы будете искать только одну строку, а не 20/25 строк. Более того, аргумент seekg()
является абсолютной позицией, поэтому вы не должны его отрицать.
EDIT: вы также должны инициализировать pos
до нуля, так что если первый ключ, который пользователь нажимает, - p
вы начинаете поиск в начале файла. В противном случае, если p
является первым нажатием клавиши, поведение не определено, так как вы ищете неинициализированное смещение.
Вы также должны проверять EOF каждый раз, когда пытаетесь прочитать строку, чтобы ваша программа вела себя правильно, когда достигнут конец файла.
ios_base::cur
. Версия с 1 аргументом seekg()
занимает абсолютную позицию в файле. См. Cplusplus.com/reference/istream/istream/seekg
Вот предлагаемая реализация. Не стесняйтесь задавать вопросы о том, как это работает, если это не ясно.
Среди основных функций
Использует класс для инкапсуляции данных и методов
#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;
}
Я бы не стал так сложно. Просто прочитайте файл в векторе при запуске программы и поймите ввод с клавиатуры (не тестировался):
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;
//...