Is there a way to read a file backwards, line by line, without having to go through the file from the beginning to start reading backwards?
-
2You could read the lines of the file into a `vector` and reverse over it. – hmjd May 30 '12 at 10:04
-
@hmjd This should be an answer, IMO. – jrok May 30 '12 at 10:05
7 Answers
Use a memory-mapped file and walk backwards. The OS will page in the needed parts of the file in reverse order.

- 89,048
- 55
- 235
- 380
-
That's an idea too, although often mapping a file is not exactly straight forward (Especially the first time!) – Alexis Wilke May 31 '12 at 09:07
As per comment, a possible (quite simple) alternative would be read the lines into a vector
. For example:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main()
{
std::ifstream in("main.cpp");
if (in.is_open())
{
std::vector<std::string> lines_in_reverse;
std::string line;
while (std::getline(in, line))
{
// Store the lines in reverse order.
lines_in_reverse.insert(lines_in_reverse.begin(), line);
}
}
}
EDIT:
As per jrok's and Loki Astari's comments, push_back()
would be more efficient but the lines would be in file order, so reverse iteration (reverse_iterator
) or std::reverse()
would be necessary:
std::vector<std::string> lines_in_order;
std::string line;
while (std::getline(in, line))
{
lines_in_order.push_back(line);
}
-
4You could use `std::reverse` after the read is complete or just iterate with `reverse_iterator`. – jrok May 30 '12 at 10:20
-
@jrok, the code inserts at the front of the vector as it stands, so the lines will already be in reverse order so no form of reverse is required.. If `push_back` was used, then yes, use a form of reverse. – hmjd May 30 '12 at 10:43
-
1Im going to guess that moving the seek to the back of the file and then iterating forwards would be better performance-wise? – intrigued_66 May 30 '12 at 10:45
-
@hmjd Yes, I said it because I imagine combination os `push_back`s followed by a `reverse` would be faster. – jrok May 30 '12 at 10:46
-
@user1107474, I honestly don't know. FWIW, my approach is to keep it simple as possible and if performance becomes an issue then investigate other alternatives. – hmjd May 30 '12 at 10:47
-
If you are using a vector. I would think it would be much more efficient to push_back() then reverse the list after you had finished. An insert at the beginning each time forces the whole vector to be shuffled up one position each time you do an insert. Alternatively you could use a deque. – Martin York May 30 '12 at 11:22
-
So with the edited version would I still need to use the reverse_iterator? or is the push_back achieving the reversal? – intrigued_66 May 30 '12 at 13:34
-
2No, you need to use the `reverse_iterator` or `std::reverse(lines_in_order.begin(), lines_in_order.end());` and then `iterator`. – hmjd May 30 '12 at 13:36
-
If you always end up reading the entire file, then this is a good solution. For a tool such as tail, that's incredibly bad. tail has to work on 2Gb file at lightning speed. Also, this solution means you read all the strings in memory and keep them all there... – Alexis Wilke May 31 '12 at 09:29
-
This is bad for big files. It takes more time push the file in string vector. – Master James Apr 10 '19 at 09:03
Slightly improved version will be this:-
1)Seek to the last-1 position
2)Get the last-1 position
3)Read a char and print it;
4)seek 2 pos back;
5)repeat 3 &4 for last-1
times;
ifstream in;
in.open("file.txt");
char ch;
int pos;
in.seekg(-1,ios::end);
pos=in.tellg();
for(int i=0;i<pos;i++)
{
ch=in.get();
cout<<ch;
in.seekg(-2,ios::cur);
}
in.close();

- 470
- 7
- 15
The short answer would be no. However, you can use the seek() function to move your pointer to where you want to go. Then read() some data from that point. If you know well how to manage buffers, then it should be pretty quick because you can read and cache the data and then search for the previous newline character(s). Have fun with \r\n which will be inverted...
-- Update: some elaboration on the possible algorithm --
This is not valid code, but it should give you an idea of what I'm trying to say here
File reads:
int fpos = in.size() - BUFSIZ;
char buf[BUFSIZ];
in.seek(fpos);
in.read(buf, BUFSIZ);
fpos -= BUFSIZ; // repeat until fpos < 0, although think of size % BUFSIZ != 0
// now buf has characters... reset buffer position
int bpos = BUFSIZ - 1;
Getting string:
// first time you need to call the read
if(bpos == -1) do_a_read();
// getting string
std::string s;
while(bpos >= 0 && buf[bpos] != '\n') {
s.insert(0, 1, buf[bpos]);
--bpos;
}
// if bpos == -1 and buf[0] != '\n' then you need to read another BUFSIZ chars
// and repeat the previous loop...
// before leaving, skip all '\n'
while(bpos >= 0 && buf[bpos] == '\n') {
--bpos;
}
return s;
To ease with '\r', you could have a first pass that transforms all '\r' to '\n'. Otherwise, all the tests of '\n' need to also test for '\r'.

- 19,179
- 10
- 84
- 156
-
@user1107474: "line by line" is just a matter of interpreting `\r\n` bytes as newlines. If you read bytes backwards, and interpret the newline bytes yourself, you can certainly read lines backwards. It's just not standard functionality. – MSalters May 30 '12 at 11:15
-
A little note here... the s.insert(0, 1, char) is SLOW. If you want to speed up, you'll want to save the end point (bpos before entering the while) and the start point (bpos after the while) and add that string to the result at once. – Alexis Wilke May 31 '12 at 09:26
Open the file for read, call
fseek()
to seek to the end of the file, then callftell()
to get the length of the file. Alternatively you can get the file length by callingstat()
orfstat()
Allocate a buffer pointer to the file size obtained in #1, above.
Read the entire file into that buffer -- you can probably use
fread()
to read the file all in one shot (assuming the file is small enough).Use another char pointer to transverse the file from end to beginning of the buffer.

- 1,874
- 1
- 20
- 32
-
1Assuming the files can easily fit in memory, this is a good, easy solution. – Alexis Wilke May 31 '12 at 09:30
My answer is similar to ones that use a vector
to store the lines of the file, but I would instead use a list
.
Imagine you have the following text in a file called input.txt
:
hello
there
friend
I would read the file line-by-line, pushing each line not to the back of my list
but to its front. Using this rather than push_back
has the same effect as reading the contents of the file line-by-line into a vector
and then reversing it or iterating through it backwards.
#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <iterator>
#include <algorithm>
int main(void) {
std::ifstream file;
file.open("input.txt");
// Make sure the file opened properly
std::list<std::string> list;
std::string buffer;
while (std::getline(file, buffer)) {
list.push_front(buffer);
}
file.close();
std::copy(
list.begin(),
list.end(),
std::ostream_iterator<std::string>(std::cout, "\n")
);
return 0;
}
(Note that the bit at the bottom with std::copy
is just to print the contents of the list with a newline character as a delimiter between elements.)
This then prints:
friend
there
hello

- 464
- 4
- 13
this might help.
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream myFile("my.txt");
int count;
cout << "Enter the number of lines u want to print ";
cin >> count;
char c;
string str = "";
for (int i = 1; i <= 10000; i++)
{
myFile.seekg(-i, std::ios::end);
myFile.get(c);
str += c;
if (c == '\n')
{
reverse(str.begin(), str.end());
count--;
cout << str;
str.clear();
}
if (count == 0)
{
break;
}
}
cout << endl;
return 0;
}

- 1
-
1Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 15 '22 at 11:17