Есть ли способ прочитать файл в обратном направлении, по очереди, без необходимости прокручивать файл с самого начала, чтобы начать чтение назад?
Прочитать файл назад?
Ответ 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);
}
Ответ 2
Используйте файл с отображением памяти и пройдите назад. ОС будет размещаться в необходимых частях файла в обратном порядке.
Ответ 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