Прочитать файл назад?

Есть ли способ прочитать файл в обратном направлении, по очереди, без необходимости прокручивать файл с самого начала, чтобы начать чтение назад?

Ответ 1

В соответствии с комментарием, возможная (довольно простая) альтернатива будет читать строки в vector. Например:

#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:

В соответствии с jrok и комментариями Loki Astari push_back() будет более эффективным, но строки будут в порядке файлов, поэтому потребуется обратная итерация (reverse_iterator) или std::reverse():

    std::vector<std::string> lines_in_order;
    std::string line;
    while (std::getline(in, line))
    {
        lines_in_order.push_back(line);
    }

Ответ 3

  • Откройте файл для чтения, вызовите fseek() для поиска в конце файла, затем вызовите ftell(), чтобы получить длину файла. В качестве альтернативы вы можете получить длину файла, вызвав stat() или fstat()

  • Выделите буферный указатель на размер файла, полученный в # 1 выше.

  • Прочитайте весь файл в этом буфере - возможно, вы можете использовать fread() для чтения файла всего за один снимок (при условии, что файл достаточно мал).

  • Используйте другой указатель char для поперечного перемещения файла с конца на начало буфера.

Ответ 4

Короткий ответ будет отрицательным. Однако вы можете использовать функцию seek(), чтобы переместить указатель туда, куда вы хотите пойти. Затем прочитайте() некоторые данные с этой точки. Если вы хорошо знаете, как управлять буферами, то это должно быть довольно быстро, потому что вы можете читать и кэшировать данные, а затем искать предыдущие символы новой строки. Получайте удовольствие от \r\n, который будет инвертирован...

- Обновление: некоторая разработка возможного алгоритма -

Это недопустимый код, но он должен дать вам представление о том, что я пытаюсь сказать здесь.

Файл читает:

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;

Получение строки:

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

Чтобы облегчить использование '\ r', вы можете получить первый проход, который преобразует все '\ r' в '\n'. В противном случае все тесты '\n' также должны быть проверены на '\ r'.

Ответ 5

Немного улучшенная версия будет следующей:
1) Ищите последнюю позицию

2) Получите последнюю позицию

3) Прочтите char и распечатайте его.
4) искать 2 pos назад;
5) повторите 3 & 4 для last-1 раз;

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

Ответ 6

Мой ответ похож на те, которые используют vector для хранения строк файла, но я бы вместо этого использовал list.

Представьте, что у вас есть следующий текст в файле с именем input.txt:

hello
there
friend

Я бы прочитал файл построчно, переместив каждую строку не в конец list а в начало. Использование этого вместо push_back имеет тот же эффект, что и чтение файла строки построчно в vector с последующим обращением его или повторением в обратном направлении.

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

(Обратите внимание, что бит внизу с std::copy предназначен только для печати содержимого списка с символом новой строки в качестве разделителя между элементами.)

Это тогда печатает:

friend
there
hello