7

我正在尝试编写一个带有菜单的程序,该菜单以几种不同的方式从文本文件中读取。我仍在处理菜单选项#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;
}
4

3 回答 3

17

以下是我对该问题的解决方案。打开文件时,我使用 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);
    }
}
于 2015-01-03T00:53:26.910 回答
4

ios::end实际上并不表示seekg应该向后寻找;相反,它只是表示偏移量是相对于文件末尾的。(是的,我认为调用类是一个糟糕的命名约定ios_base::seekdir。)据我所知,没有标准的方法来实际向后读取文件,尽管这里有一些关于如何模拟这样做的建议:读取文件向后?

于 2013-04-04T21:56:00.270 回答
4

除非您的主要目的是浪费时间,否则您希望找到正确的位置,向前读取文件,然后反转内存中的数据。如果您正在读取大量数据,并且一次只需要少量内存,则可以稍微修改一下以读取(例如)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 标准规定,如果您打开一个用于读取和写入的流,则当/如果您从读取切换到写入(反之亦然)时,您必须在流上进行搜索。正因为如此,很多在流上查找的实现在每次查找时都会刷新缓冲区,以防万一您可能从写入切换到读取,并且需要读回查找之前写入缓冲区中的数据。

通常这无关紧要:无论如何,寻道通常会将您带到缓冲区中的范围之外,因此您最终不得不从磁盘读取数据。但是,在此处处理的特定情况下,只要您“向前”读取数据,然后将其反转而不是对每个字节进行搜索,缓冲就可以很好地工作。虽然最好使用实际的最大缓冲区,但即使是相当小的缓冲区也会对速度产生很大影响。

于 2016-10-14T00:20:11.173 回答