Я хочу показать содержимое текстового файла 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()
это абсолютная позиция, поэтому не стоит отрицать ее.
РЕДАКТИРОВАТЬ: Вы также должны инициализировать pos
в ноль, так что если первый ключ, который пользователь нажимает p
Вы ищете начало файла. В противном случае, если p
это первое нажатие клавиши, поведение которого не определено, так как вы ищете неинициализированное смещение.
Вы также должны проверять EOF каждый раз, когда пытаетесь прочитать строку, чтобы ваша программа работала правильно, когда достигнут конец файла.
Я бы не стал делать это так сложно. Просто прочитайте файл в векторе при запуске программы и поймайте ввод с клавиатуры (не проверено):
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;
//...
Вот предлагаемая реализация. Не стесняйтесь задавать вопросы о том, как это работает, если это не ясно.
Среди основных особенностей
Использует класс для инкапсуляции данных и методов
#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;
}