C++ Reading file backwards from the end of the file

一世执手 提交于 2019-12-01 20:30:58

问题


I am trying to write a program with a menu that reads from a text file a few different ways. I'm just working on menu option #2 still (reading backwards from the end of the file), but I can't wrap my head around what I'm doing wrong. I've been at this for a few days now and just can't find any good resources to help on this. Any help would be appreciated.

#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;
}

回答1:


The following is my solution to the question. When open the file, I use ios::ate to set the file position to the end of the file and use seekg method to read back. I am not sure whether there is a more efficient way to solve this question.

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);
    }
}



回答2:


ios::end doesn't actually indicate that seekg should seek backward; rather, it simply indicates that offsets are relative to the end of the file. (Yes, I think it's a poor naming convention to call the class ios_base::seekdir.) As far as I know, there is no standard way to actually read a file backwards, though there are some suggestions here for how to emulate doing so: Read a file backwards?




回答3:


Unless your primary intent is to waste time, you want to seek to the correct position, read through the file frontwards, then reverse the data in memory. If you're reading a large amount, and only want a small amount in memory at a time, you can modify that a little to read (for example) 16 or 64 Kilobyte chunks.

Once you have a chunk of data in memory, you have two choices. You can either process that from its end backward toward the beginning, or you can reverse it, then process it from beginning to end. The latter might look something like this:

// 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;
}

Attempting to actually read the file backward can (and often will) lead to a serious performance problem. To be specific, the standard library will often flush its buffers any time you do a seek on a stream, so each reading immediately following a seek will typically result calling a kernel function to read data from disk (or at least from the OS's cache).

In case you care why that is: the C++ standard bases its description of how files work on the C standard. The C standard says that if you open a stream for both reading and writing, you have to do a seek on the stream when/if you switch from reading to writing (or vice versa). Because of this, quite a few implementations of seeking on a stream flush the buffer at every seek, just in case you might be switching from writing to reading, and need to read back in data that was in the write buffer before the seek.

Usually this doesn't matter much: a seek will often take you outside the range that's in the buffer anyway, so you'd end up having to read data from the disk anyway. In the specific case being dealt with here, however, buffering can work quite nicely as long as you read the data "frontwards", then reverse it instead of doing a seek for each byte. Although it's best to use the biggest buffer that's practical, even a fairly small buffer can make a big difference in speed.



来源:https://stackoverflow.com/questions/15822062/c-reading-file-backwards-from-the-end-of-the-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!