我正在尝试编写一个带有菜单的程序,该菜单可以通过几种不同的方式从文本文件中读取。我只是在处理菜单选项#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;
}
答案 0 :(得分:8)
以下是我对该问题的解决方案。 打开文件时,我使用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);
}
}
答案 1 :(得分:1)
ios::end
实际上并不表示seekg
应该向后搜索;相反,它只是表明偏移量是相对于文件末尾的。 (是的,我认为调用类ios_base::seekdir
是一个糟糕的命名约定。)据我所知,没有标准的方法来实际向后读取文件,尽管这里有一些关于如何模拟做的建议所以:Read a file backwards?
答案 2 :(得分:1)
除非您的主要目的是浪费时间,否则您需要寻找正确的位置,向前读取文件,然后反转内存中的数据。如果您正在阅读大量内容,并且一次只想要少量内存,则可以稍微修改一下(例如)16或64个Kilobyte块。
一旦你在内存中有一大块数据,你有两个选择。您可以从结尾向后处理它,也可以将其反转,然后从头到尾处理它。后者可能看起来像这样:
// 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;
}
尝试向后实际读取文件可能(并且经常会)导致严重的性能问题。具体来说,标准库通常会在您对流进行搜索时刷新其缓冲区,因此每次读取后的读取通常会导致调用内核函数从磁盘读取数据(或者至少从OS中读取数据) ;缓存)。
如果您关心原因:C ++标准基于文件如何在C标准上工作的描述。 C标准说,如果你打开一个流读取和写入,你必须在流/当你从阅读切换到写(或反之亦然)时搜索流。因此,在每次搜索时,有很多寻求流的实现会刷新缓冲区,以防万一您可能正在从写入切换到读取,并且需要在搜索之前读回写入缓冲区中的数据。 / p>
通常这并不重要:搜索通常会让你超出缓冲区中的范围,所以你最终不得不阅读无论如何,来自磁盘的数据。然而,在这里处理的具体情况中,只要你读取数据&#34;向前&#34;然后反转它而不是对每个字节进行搜索,缓冲就可以很好地工作。尽管使用最实用的最大缓冲区是最好的,但即使是相当小的缓冲区也可以在速度上产生很大的不同。