Я пытаюсь написать программу с меню, которое читает из текстового файла несколько разных способов. Я все еще работаю над пунктом меню № 2 (читая в обратном направлении от конца файла), но я не могу понять, что я делаю неправильно. Я занимаюсь этим уже несколько дней и просто не могу найти хороших ресурсов, чтобы помочь в этом. Любая помощь будет оценена.
#include <iostream>
#include <string>
#include <iomanip>
#include <istream>
#include <math.h>
#include <fstream>
using namespace std;
const int SIZE = 20;
typedef char String[SIZE];
//prototypes
void Menu(int &);
void ReadFile(ifstream &);
void BackwardFile(ifstream &,long &);
long CountFile(ifstream &,long &);
int main()
{
char filename[]= "grades.txt";
int choice;
long numBytes;
ifstream InList;
InList.open(filename);
if(InList.good())
{
do
{
Menu(choice);
switch(choice)
{
case 1:
ReadFile(InList);
break;
case 2:
CountFile(InList,numBytes);
BackwardFile(InList,numBytes);
break;
case 3:
cout << "Pick a start position between 0 - " << numBytes << endl;
break;
/*case 4:*/
case 5:
cout << "\n GOOD BYE." << endl << endl;
break;
}
}while (choice != 5);
}
else
cout << "File did not open successfully." << endl << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
void Menu(int &choice)
{
cout << "\n Choose an option:";
cout << "\n...................................";
cout << "\n 1- Display All Contents of the File";
cout << "\n 2- Display Content in Reverse Order";
cout << "\n 3- Display from Point A to Point B";
cout << "\n 4- Display from Point B to Point A";
cout << "\n 5- Exit";
cout << "\n\n Enter your choice: ";
cin >> choice;
}
void ReadFile(ifstream& inFile)
{
char byte;
inFile.clear();
cout<< "\nReading contents from the file:" <<endl;
if(inFile)
{
inFile.get(byte);
while(inFile.good())
{
cout << byte;
inFile.get(byte);
}
}
inFile.close();
}
void BackwardFile(ifstream& inFile, long& numBytes)
{
char byte;
inFile.clear();
cout<< "\nReading contents backwards from the file:" <<endl;
inFile.seekg(numBytes, ios::end);
while(inFile)
{
inFile.get(byte);
cout << byte;
numBytes--;
inFile.seekg(numBytes);
}
inFile.close();
}
long CountFile(ifstream& inFile, long& numBytes)
{
inFile.seekg(0L, ios::end);
numBytes = inFile.tellg();
return numBytes;
}
Ниже мое решение вопроса.
Когда я открываю файл, я использую ios :: ate, чтобы установить позицию файла в конец
файла и используйте метод seekg для чтения назад.
Я не уверен, есть ли более эффективный способ решить этот вопрос.
void readFile(char *fileName){
char c;
std::ifstream myFile(fileName,std::ios::ate);
std::streampos size = myFile.tellg();
for(int i=1;i<=size;i++){
myFile.seekg(-i,std::ios::end);
myFile.get(c);
printf("%c\n",c);
}
}
ios::end
на самом деле не означает, что seekg
следует искать назад; скорее это просто означает, что смещения относятся к концу файла. (Да, я думаю, что это плохое соглашение об именах ios_base::seekdir
Насколько я знаю, не существует стандартного способа на самом деле прочитать файл в обратном направлении, хотя здесь есть несколько советов о том, как эмулировать это: Читать файл задом наперед?
Если ваше основное намерение не состоит в том, чтобы тратить время, вы хотите найти правильную позицию, прочитать файл вперед, а затем перевернуть данные в памяти. Если вы читаете большое количество и хотите, чтобы в памяти одновременно было только небольшое количество, вы можете немного изменить его, чтобы прочитать (например) 16 или 64 килобайтных кусков.
Как только у вас есть кусок данных в памяти, у вас есть два варианта. Вы можете либо обработать это от его конца назад к началу, либо вы можете повернуть его вспять, а затем обработать его от начала до конца. Последний может выглядеть примерно так:
// Warning: I have only tested this, not proven it correct.
std::vector<char> read_backwards(std::istream &is, int size) {
std::vector<char> buffer;
buffer.resize(size);
is.seekg(-size, std::ios::end);
is.read(&buffer[0], size);
std::reverse(buffer.begin(), buffer.end());
return buffer;
}
Попытка действительно прочитать файл в обратном направлении может (и часто будет) приводить к серьезной проблеме производительности. Точнее говоря, стандартная библиотека часто сбрасывает свои буферы каждый раз, когда вы выполняете поиск в потоке, поэтому каждое чтение, следующее сразу за поиском, обычно приводит к вызову функции ядра для чтения данных с диска (или, по крайней мере, из кэша ОС). ,
Если вам интересно, почему это так: стандарт C ++ основывает свое описание работы файлов на стандарте C. Стандарт C говорит, что если вы открываете поток как для чтения, так и для записи, вы должны выполнять поиск в потоке, когда / если вы переключаетесь с чтения на запись (или наоборот). Из-за этого довольно много реализаций поиска в потоке очищают буфер при каждом поиске, на случай, если вы, возможно, переключаетесь с записи на чтение, и вам нужно прочитать данные, которые были в буфере записи, перед поиском.
Обычно это не имеет большого значения: в любом случае поиск часто выводит вас за пределы диапазона, который находится в буфере, так что вам все равно придется читать данные с диска. Однако в конкретном случае, о котором идет речь, буферизация может работать довольно хорошо, пока вы читаете данные «вперед», а затем обращаетесь к ним вместо поиска каждого байта. Хотя лучше всего использовать самый большой из возможных буферов, даже довольно маленький буфер может сильно повлиять на скорость.